Give some NetworkLoadMetrics to WebCoreNSURLSession's delegate
https://bugs.webkit.org/show_bug.cgi?id=211759
<rdar://problem/62909440>

Patch by Alex Christensen <achristensen@webkit.org> on 2020-05-12
Reviewed by Jer Noble.

Source/WebCore:

This required packaging the fetchStart time with the rest of the time deltas,
passing a const NetworkLoadMetrics& down to the media loader, and packaging the data up
in an ObjC object that pretends to be NSURLSessionTaskMetrics, just like WebCoreNSURLSession
pretends to be an NSURLSession.

I manually verified the NSDates are correct.  This is not straightforward to automate tests for
because of the inherant dynamic nature of timing data, and because our other WebCoreNSURLSession
tests use WebKitLegacy, and that approach won't work here because we are only hooking up data from
NSURLSession, which is only used in modern WebKit.

* Modules/beacon/NavigatorBeacon.cpp:
(WebCore::NavigatorBeacon::notifyFinished):
* Modules/beacon/NavigatorBeacon.h:
* bindings/js/CachedModuleScriptLoader.cpp:
(WebCore::CachedModuleScriptLoader::notifyFinished):
* bindings/js/CachedModuleScriptLoader.h:
* dom/LoadableClassicScript.cpp:
(WebCore::LoadableClassicScript::notifyFinished):
* dom/LoadableClassicScript.h:
* html/HTMLImageLoader.cpp:
(WebCore::HTMLImageLoader::notifyFinished):
* html/HTMLImageLoader.h:
* html/ImageDocument.cpp:
(WebCore::ImageDocument::finishedParsing):
* loader/ApplicationManifestLoader.cpp:
(WebCore::ApplicationManifestLoader::notifyFinished):
* loader/ApplicationManifestLoader.h:
* loader/CrossOriginPreflightChecker.cpp:
(WebCore::CrossOriginPreflightChecker::notifyFinished):
* loader/CrossOriginPreflightChecker.h:
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::notifyFinished):
* loader/DocumentLoader.h:
* loader/DocumentThreadableLoader.cpp:
(WebCore::DocumentThreadableLoader::notifyFinished):
* loader/DocumentThreadableLoader.h:
* loader/ImageLoader.cpp:
(WebCore::ImageLoader::notifyFinished):
* loader/ImageLoader.h:
* loader/LinkLoader.cpp:
(WebCore::LinkLoader::notifyFinished):
* loader/LinkLoader.h:
* loader/LinkPreloadResourceClients.h:
* loader/MediaResourceLoader.cpp:
(WebCore::MediaResource::notifyFinished):
* loader/MediaResourceLoader.h:
* loader/SubresourceLoader.cpp:
(WebCore::SubresourceLoader::didReceiveResponse):
(WebCore::SubresourceLoader::didFinishLoading):
* loader/TextTrackLoader.cpp:
(WebCore::TextTrackLoader::notifyFinished):
* loader/TextTrackLoader.h:
* loader/appcache/ApplicationCacheResourceLoader.cpp:
(WebCore::ApplicationCacheResourceLoader::responseReceived):
(WebCore::ApplicationCacheResourceLoader::notifyFinished):
* loader/appcache/ApplicationCacheResourceLoader.h:
* loader/cache/CachedApplicationManifest.cpp:
(WebCore::CachedApplicationManifest::finishLoading):
* loader/cache/CachedApplicationManifest.h:
* loader/cache/CachedCSSStyleSheet.cpp:
(WebCore::CachedCSSStyleSheet::finishLoading):
(WebCore::CachedCSSStyleSheet::checkNotify):
* loader/cache/CachedCSSStyleSheet.h:
* loader/cache/CachedFont.cpp:
(WebCore::CachedFont::finishLoading):
(WebCore::CachedFont::checkNotify):
* loader/cache/CachedFont.h:
* loader/cache/CachedImage.cpp:
(WebCore::CachedImage::finishLoading):
* loader/cache/CachedImage.h:
* loader/cache/CachedRawResource.cpp:
(WebCore::CachedRawResource::updateBuffer):
(WebCore::CachedRawResource::finishLoading):
* loader/cache/CachedRawResource.h:
* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::load):
(WebCore::CachedResource::checkNotify):
(WebCore::CachedResource::finishLoading):
(WebCore::CachedResource::error):
(WebCore::CachedResource::cancelLoad):
(WebCore::CachedResource::didAddClient):
* loader/cache/CachedResource.h:
* loader/cache/CachedResourceClient.h:
(WebCore::CachedResourceClient::notifyFinished):
* loader/cache/CachedSVGDocument.cpp:
(WebCore::CachedSVGDocument::finishLoading):
* loader/cache/CachedSVGDocument.h:
* loader/cache/CachedScript.cpp:
(WebCore::CachedScript::finishLoading):
* loader/cache/CachedScript.h:
* loader/cache/CachedTextTrack.cpp:
(WebCore::CachedTextTrack::finishLoading):
* loader/cache/CachedTextTrack.h:
* loader/cache/CachedXSLStyleSheet.cpp:
(WebCore::CachedXSLStyleSheet::finishLoading):
(WebCore::CachedXSLStyleSheet::checkNotify):
* loader/cache/CachedXSLStyleSheet.h:
* loader/cache/KeepaliveRequestTracker.cpp:
(WebCore::KeepaliveRequestTracker::notifyFinished):
* loader/cache/KeepaliveRequestTracker.h:
* loader/icon/IconLoader.cpp:
(WebCore::IconLoader::notifyFinished):
* loader/icon/IconLoader.h:
* platform/graphics/PlatformMediaResourceLoader.h:
(WebCore::PlatformMediaResourceClient::loadFinished):
* platform/graphics/avfoundation/objc/WebCoreAVFResourceLoader.mm:
(WebCore::CachedResourceMediaLoader::notifyFinished):
* platform/network/NetworkLoadMetrics.h:
(WebCore::NetworkLoadMetrics::isolatedCopy const):
(WebCore::NetworkLoadMetrics::operator== const):
(WebCore::NetworkLoadMetrics::encode const):
(WebCore::NetworkLoadMetrics::decode):
(WTF::Persistence::Coder<Optional<WebCore::NetworkLoadPriority>>::encode): Deleted.
(WTF::Persistence::Coder<Optional<WebCore::NetworkLoadPriority>>::decode): Deleted.
* platform/network/cocoa/NetworkLoadMetrics.mm:
(WebCore::copyTimingData):
* platform/network/cocoa/WebCoreNSURLSession.mm:
(networkLoadMetricsDate):
(-[WebCoreNSURLSessionTaskTransactionMetrics _initWithMetrics:]):
(-[WebCoreNSURLSessionTaskTransactionMetrics fetchStartDate]):
(-[WebCoreNSURLSessionTaskTransactionMetrics domainLookupStartDate]):
(-[WebCoreNSURLSessionTaskTransactionMetrics domainLookupEndDate]):
(-[WebCoreNSURLSessionTaskTransactionMetrics connectStartDate]):
(-[WebCoreNSURLSessionTaskTransactionMetrics secureConnectionStartDate]):
(-[WebCoreNSURLSessionTaskTransactionMetrics connectEndDate]):
(-[WebCoreNSURLSessionTaskTransactionMetrics requestStartDate]):
(-[WebCoreNSURLSessionTaskTransactionMetrics responseStartDate]):
(-[WebCoreNSURLSessionTaskTransactionMetrics responseEndDate]):
(-[WebCoreNSURLSessionTaskMetrics _initWithMetrics:]):
(-[WebCoreNSURLSessionTaskMetrics transactionMetrics]):
(WebCore::WebCoreNSURLSessionDataTaskClient::loadFinished):
(-[WebCoreNSURLSessionDataTask _finish]):
(-[WebCoreNSURLSessionDataTask _resource:loadFinishedWithError:metrics:]):
(-[WebCoreNSURLSessionDataTask resource:accessControlCheckFailedWithError:]):
(-[WebCoreNSURLSessionDataTask resource:loadFailedWithError:]):
(-[WebCoreNSURLSessionDataTask resourceFinished:metrics:]):
(-[WebCoreNSURLSessionDataTask _resource:loadFinishedWithError:]): Deleted.
(-[WebCoreNSURLSessionDataTask resourceFinished:]): Deleted.
* rendering/RenderElement.cpp:
(WebCore::RenderElement::notifyFinished):
* rendering/RenderElement.h:
* rendering/RenderImage.cpp:
(WebCore::RenderImage::notifyFinished):
* rendering/RenderImage.h:
* rendering/RenderLayerFilters.cpp:
(WebCore::RenderLayerFilters::notifyFinished):
* rendering/RenderLayerFilters.h:
* svg/SVGFEImageElement.cpp:
(WebCore::SVGFEImageElement::notifyFinished):
* svg/SVGFEImageElement.h:
* svg/SVGUseElement.cpp:
(WebCore::SVGUseElement::notifyFinished):
* svg/SVGUseElement.h:

Source/WebKit:

This also reduces duplicate lookups in RemoteMediaResourceManager

* GPUProcess/media/RemoteMediaResource.cpp:
(WebKit::RemoteMediaResource::loadFinished):
* GPUProcess/media/RemoteMediaResource.h:
* GPUProcess/media/RemoteMediaResourceManager.cpp:
(WebKit::RemoteMediaResourceManager::responseReceived):
(WebKit::RemoteMediaResourceManager::redirectReceived):
(WebKit::RemoteMediaResourceManager::dataSent):
(WebKit::RemoteMediaResourceManager::dataReceived):
(WebKit::RemoteMediaResourceManager::accessControlCheckFailed):
(WebKit::RemoteMediaResourceManager::loadFailed):
(WebKit::RemoteMediaResourceManager::loadFinished):
* GPUProcess/media/RemoteMediaResourceManager.h:
* GPUProcess/media/RemoteMediaResourceManager.messages.in:
* NetworkProcess/cocoa/NetworkSessionCocoa.mm:
(-[WKNetworkSessionDelegate URLSession:task:didFinishCollectingMetrics:]):
* WebProcess/GPU/media/RemoteMediaResourceProxy.cpp:
(WebKit::RemoteMediaResourceProxy::loadFinished):
* WebProcess/GPU/media/RemoteMediaResourceProxy.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@261597 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index daedf3c..bc3a59f 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,165 @@
+2020-05-12  Alex Christensen  <achristensen@webkit.org>
+
+        Give some NetworkLoadMetrics to WebCoreNSURLSession's delegate
+        https://bugs.webkit.org/show_bug.cgi?id=211759
+        <rdar://problem/62909440>
+
+        Reviewed by Jer Noble.
+
+        This required packaging the fetchStart time with the rest of the time deltas,
+        passing a const NetworkLoadMetrics& down to the media loader, and packaging the data up
+        in an ObjC object that pretends to be NSURLSessionTaskMetrics, just like WebCoreNSURLSession
+        pretends to be an NSURLSession.
+
+        I manually verified the NSDates are correct.  This is not straightforward to automate tests for
+        because of the inherant dynamic nature of timing data, and because our other WebCoreNSURLSession
+        tests use WebKitLegacy, and that approach won't work here because we are only hooking up data from
+        NSURLSession, which is only used in modern WebKit.
+
+        * Modules/beacon/NavigatorBeacon.cpp:
+        (WebCore::NavigatorBeacon::notifyFinished):
+        * Modules/beacon/NavigatorBeacon.h:
+        * bindings/js/CachedModuleScriptLoader.cpp:
+        (WebCore::CachedModuleScriptLoader::notifyFinished):
+        * bindings/js/CachedModuleScriptLoader.h:
+        * dom/LoadableClassicScript.cpp:
+        (WebCore::LoadableClassicScript::notifyFinished):
+        * dom/LoadableClassicScript.h:
+        * html/HTMLImageLoader.cpp:
+        (WebCore::HTMLImageLoader::notifyFinished):
+        * html/HTMLImageLoader.h:
+        * html/ImageDocument.cpp:
+        (WebCore::ImageDocument::finishedParsing):
+        * loader/ApplicationManifestLoader.cpp:
+        (WebCore::ApplicationManifestLoader::notifyFinished):
+        * loader/ApplicationManifestLoader.h:
+        * loader/CrossOriginPreflightChecker.cpp:
+        (WebCore::CrossOriginPreflightChecker::notifyFinished):
+        * loader/CrossOriginPreflightChecker.h:
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::notifyFinished):
+        * loader/DocumentLoader.h:
+        * loader/DocumentThreadableLoader.cpp:
+        (WebCore::DocumentThreadableLoader::notifyFinished):
+        * loader/DocumentThreadableLoader.h:
+        * loader/ImageLoader.cpp:
+        (WebCore::ImageLoader::notifyFinished):
+        * loader/ImageLoader.h:
+        * loader/LinkLoader.cpp:
+        (WebCore::LinkLoader::notifyFinished):
+        * loader/LinkLoader.h:
+        * loader/LinkPreloadResourceClients.h:
+        * loader/MediaResourceLoader.cpp:
+        (WebCore::MediaResource::notifyFinished):
+        * loader/MediaResourceLoader.h:
+        * loader/SubresourceLoader.cpp:
+        (WebCore::SubresourceLoader::didReceiveResponse):
+        (WebCore::SubresourceLoader::didFinishLoading):
+        * loader/TextTrackLoader.cpp:
+        (WebCore::TextTrackLoader::notifyFinished):
+        * loader/TextTrackLoader.h:
+        * loader/appcache/ApplicationCacheResourceLoader.cpp:
+        (WebCore::ApplicationCacheResourceLoader::responseReceived):
+        (WebCore::ApplicationCacheResourceLoader::notifyFinished):
+        * loader/appcache/ApplicationCacheResourceLoader.h:
+        * loader/cache/CachedApplicationManifest.cpp:
+        (WebCore::CachedApplicationManifest::finishLoading):
+        * loader/cache/CachedApplicationManifest.h:
+        * loader/cache/CachedCSSStyleSheet.cpp:
+        (WebCore::CachedCSSStyleSheet::finishLoading):
+        (WebCore::CachedCSSStyleSheet::checkNotify):
+        * loader/cache/CachedCSSStyleSheet.h:
+        * loader/cache/CachedFont.cpp:
+        (WebCore::CachedFont::finishLoading):
+        (WebCore::CachedFont::checkNotify):
+        * loader/cache/CachedFont.h:
+        * loader/cache/CachedImage.cpp:
+        (WebCore::CachedImage::finishLoading):
+        * loader/cache/CachedImage.h:
+        * loader/cache/CachedRawResource.cpp:
+        (WebCore::CachedRawResource::updateBuffer):
+        (WebCore::CachedRawResource::finishLoading):
+        * loader/cache/CachedRawResource.h:
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::load):
+        (WebCore::CachedResource::checkNotify):
+        (WebCore::CachedResource::finishLoading):
+        (WebCore::CachedResource::error):
+        (WebCore::CachedResource::cancelLoad):
+        (WebCore::CachedResource::didAddClient):
+        * loader/cache/CachedResource.h:
+        * loader/cache/CachedResourceClient.h:
+        (WebCore::CachedResourceClient::notifyFinished):
+        * loader/cache/CachedSVGDocument.cpp:
+        (WebCore::CachedSVGDocument::finishLoading):
+        * loader/cache/CachedSVGDocument.h:
+        * loader/cache/CachedScript.cpp:
+        (WebCore::CachedScript::finishLoading):
+        * loader/cache/CachedScript.h:
+        * loader/cache/CachedTextTrack.cpp:
+        (WebCore::CachedTextTrack::finishLoading):
+        * loader/cache/CachedTextTrack.h:
+        * loader/cache/CachedXSLStyleSheet.cpp:
+        (WebCore::CachedXSLStyleSheet::finishLoading):
+        (WebCore::CachedXSLStyleSheet::checkNotify):
+        * loader/cache/CachedXSLStyleSheet.h:
+        * loader/cache/KeepaliveRequestTracker.cpp:
+        (WebCore::KeepaliveRequestTracker::notifyFinished):
+        * loader/cache/KeepaliveRequestTracker.h:
+        * loader/icon/IconLoader.cpp:
+        (WebCore::IconLoader::notifyFinished):
+        * loader/icon/IconLoader.h:
+        * platform/graphics/PlatformMediaResourceLoader.h:
+        (WebCore::PlatformMediaResourceClient::loadFinished):
+        * platform/graphics/avfoundation/objc/WebCoreAVFResourceLoader.mm:
+        (WebCore::CachedResourceMediaLoader::notifyFinished):
+        * platform/network/NetworkLoadMetrics.h:
+        (WebCore::NetworkLoadMetrics::isolatedCopy const):
+        (WebCore::NetworkLoadMetrics::operator== const):
+        (WebCore::NetworkLoadMetrics::encode const):
+        (WebCore::NetworkLoadMetrics::decode):
+        (WTF::Persistence::Coder<Optional<WebCore::NetworkLoadPriority>>::encode): Deleted.
+        (WTF::Persistence::Coder<Optional<WebCore::NetworkLoadPriority>>::decode): Deleted.
+        * platform/network/cocoa/NetworkLoadMetrics.mm:
+        (WebCore::copyTimingData):
+        * platform/network/cocoa/WebCoreNSURLSession.mm:
+        (networkLoadMetricsDate):
+        (-[WebCoreNSURLSessionTaskTransactionMetrics _initWithMetrics:]):
+        (-[WebCoreNSURLSessionTaskTransactionMetrics fetchStartDate]):
+        (-[WebCoreNSURLSessionTaskTransactionMetrics domainLookupStartDate]):
+        (-[WebCoreNSURLSessionTaskTransactionMetrics domainLookupEndDate]):
+        (-[WebCoreNSURLSessionTaskTransactionMetrics connectStartDate]):
+        (-[WebCoreNSURLSessionTaskTransactionMetrics secureConnectionStartDate]):
+        (-[WebCoreNSURLSessionTaskTransactionMetrics connectEndDate]):
+        (-[WebCoreNSURLSessionTaskTransactionMetrics requestStartDate]):
+        (-[WebCoreNSURLSessionTaskTransactionMetrics responseStartDate]):
+        (-[WebCoreNSURLSessionTaskTransactionMetrics responseEndDate]):
+        (-[WebCoreNSURLSessionTaskMetrics _initWithMetrics:]):
+        (-[WebCoreNSURLSessionTaskMetrics transactionMetrics]):
+        (WebCore::WebCoreNSURLSessionDataTaskClient::loadFinished):
+        (-[WebCoreNSURLSessionDataTask _finish]):
+        (-[WebCoreNSURLSessionDataTask _resource:loadFinishedWithError:metrics:]):
+        (-[WebCoreNSURLSessionDataTask resource:accessControlCheckFailedWithError:]):
+        (-[WebCoreNSURLSessionDataTask resource:loadFailedWithError:]):
+        (-[WebCoreNSURLSessionDataTask resourceFinished:metrics:]):
+        (-[WebCoreNSURLSessionDataTask _resource:loadFinishedWithError:]): Deleted.
+        (-[WebCoreNSURLSessionDataTask resourceFinished:]): Deleted.
+        * rendering/RenderElement.cpp:
+        (WebCore::RenderElement::notifyFinished):
+        * rendering/RenderElement.h:
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::notifyFinished):
+        * rendering/RenderImage.h:
+        * rendering/RenderLayerFilters.cpp:
+        (WebCore::RenderLayerFilters::notifyFinished):
+        * rendering/RenderLayerFilters.h:
+        * svg/SVGFEImageElement.cpp:
+        (WebCore::SVGFEImageElement::notifyFinished):
+        * svg/SVGFEImageElement.h:
+        * svg/SVGUseElement.cpp:
+        (WebCore::SVGUseElement::notifyFinished):
+        * svg/SVGUseElement.h:
+
 2020-05-12  Said Abou-Hallawa  <sabouhallawa@apple.com>
 
         [CG] Change the UTI of the "WebP" image to be "org.webmproject.webp"
diff --git a/Source/WebCore/Modules/beacon/NavigatorBeacon.cpp b/Source/WebCore/Modules/beacon/NavigatorBeacon.cpp
index a4ffc32..d24ee29 100644
--- a/Source/WebCore/Modules/beacon/NavigatorBeacon.cpp
+++ b/Source/WebCore/Modules/beacon/NavigatorBeacon.cpp
@@ -64,7 +64,7 @@
     return "NavigatorBeacon";
 }
 
-void NavigatorBeacon::notifyFinished(CachedResource& resource)
+void NavigatorBeacon::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     if (!resource.resourceError().isNull())
         logError(resource.resourceError());
diff --git a/Source/WebCore/Modules/beacon/NavigatorBeacon.h b/Source/WebCore/Modules/beacon/NavigatorBeacon.h
index b56913d..813b751 100644
--- a/Source/WebCore/Modules/beacon/NavigatorBeacon.h
+++ b/Source/WebCore/Modules/beacon/NavigatorBeacon.h
@@ -55,7 +55,7 @@
 
     static const char* supplementName();
 
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
     void logError(const ResourceError&);
 
     Navigator& m_navigator;
diff --git a/Source/WebCore/bindings/js/CachedModuleScriptLoader.cpp b/Source/WebCore/bindings/js/CachedModuleScriptLoader.cpp
index 8402b02..352dcc4 100644
--- a/Source/WebCore/bindings/js/CachedModuleScriptLoader.cpp
+++ b/Source/WebCore/bindings/js/CachedModuleScriptLoader.cpp
@@ -75,7 +75,7 @@
     return true;
 }
 
-void CachedModuleScriptLoader::notifyFinished(CachedResource& resource)
+void CachedModuleScriptLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT_UNUSED(resource, &resource == m_cachedScript);
     ASSERT(m_cachedScript);
diff --git a/Source/WebCore/bindings/js/CachedModuleScriptLoader.h b/Source/WebCore/bindings/js/CachedModuleScriptLoader.h
index 8d7c50b..43abd87 100644
--- a/Source/WebCore/bindings/js/CachedModuleScriptLoader.h
+++ b/Source/WebCore/bindings/js/CachedModuleScriptLoader.h
@@ -64,7 +64,7 @@
 private:
     CachedModuleScriptLoader(CachedModuleScriptLoaderClient&, DeferredPromise&, CachedScriptFetcher&, RefPtr<ModuleFetchParameters>&&);
 
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
 
     CachedModuleScriptLoaderClient* m_client { nullptr };
     RefPtr<DeferredPromise> m_promise;
diff --git a/Source/WebCore/dom/LoadableClassicScript.cpp b/Source/WebCore/dom/LoadableClassicScript.cpp
index 72770d2..5dd8edb 100644
--- a/Source/WebCore/dom/LoadableClassicScript.cpp
+++ b/Source/WebCore/dom/LoadableClassicScript.cpp
@@ -70,7 +70,7 @@
     return m_cachedScript->wasCanceled();
 }
 
-void LoadableClassicScript::notifyFinished(CachedResource& resource)
+void LoadableClassicScript::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT(m_cachedScript);
     if (resource.resourceError().isAccessControl()) {
diff --git a/Source/WebCore/dom/LoadableClassicScript.h b/Source/WebCore/dom/LoadableClassicScript.h
index e5f5ac1..90c47a1 100644
--- a/Source/WebCore/dom/LoadableClassicScript.h
+++ b/Source/WebCore/dom/LoadableClassicScript.h
@@ -63,7 +63,7 @@
     {
     }
 
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
 
     CachedResourceHandle<CachedScript> m_cachedScript { };
     Optional<Error> m_error { WTF::nullopt };
diff --git a/Source/WebCore/html/HTMLImageLoader.cpp b/Source/WebCore/html/HTMLImageLoader.cpp
index b664940..b17dbcd 100644
--- a/Source/WebCore/html/HTMLImageLoader.cpp
+++ b/Source/WebCore/html/HTMLImageLoader.cpp
@@ -66,13 +66,13 @@
     return stripLeadingAndTrailingHTMLSpaces(attr);
 }
 
-void HTMLImageLoader::notifyFinished(CachedResource&)
+void HTMLImageLoader::notifyFinished(CachedResource&, const NetworkLoadMetrics& metrics)
 {
     ASSERT(image());
     CachedImage& cachedImage = *image();
 
     Ref<Element> protect(element());
-    ImageLoader::notifyFinished(cachedImage);
+    ImageLoader::notifyFinished(cachedImage, metrics);
 
     bool loadError = cachedImage.errorOccurred() || cachedImage.response().httpStatusCode() >= 400;
     if (!loadError) {
diff --git a/Source/WebCore/html/HTMLImageLoader.h b/Source/WebCore/html/HTMLImageLoader.h
index f22742e..16a7c39 100644
--- a/Source/WebCore/html/HTMLImageLoader.h
+++ b/Source/WebCore/html/HTMLImageLoader.h
@@ -34,7 +34,7 @@
     void dispatchLoadEvent() override;
     String sourceURI(const AtomString&) const override;
 
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
 };
 
 }
diff --git a/Source/WebCore/html/ImageDocument.cpp b/Source/WebCore/html/ImageDocument.cpp
index 7090fdd..f7b8dd3 100644
--- a/Source/WebCore/html/ImageDocument.cpp
+++ b/Source/WebCore/html/ImageDocument.cpp
@@ -158,7 +158,7 @@
         if (data && loader()->isLoadingMultipartContent())
             data = data->copy();
 
-        cachedImage.finishLoading(data.get());
+        cachedImage.finishLoading(data.get(), { });
         cachedImage.finish();
 
         // Report the natural image size in the page title, regardless of zoom level.
diff --git a/Source/WebCore/loader/ApplicationManifestLoader.cpp b/Source/WebCore/loader/ApplicationManifestLoader.cpp
index 612a420..5cdde58 100644
--- a/Source/WebCore/loader/ApplicationManifestLoader.cpp
+++ b/Source/WebCore/loader/ApplicationManifestLoader.cpp
@@ -115,7 +115,7 @@
     return m_processedManifest;
 }
 
-void ApplicationManifestLoader::notifyFinished(CachedResource& resource)
+void ApplicationManifestLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT_UNUSED(resource, &resource == m_resource);
     m_documentLoader.finishedLoadingApplicationManifest(*this);
diff --git a/Source/WebCore/loader/ApplicationManifestLoader.h b/Source/WebCore/loader/ApplicationManifestLoader.h
index 1264ecd..bab54e00 100644
--- a/Source/WebCore/loader/ApplicationManifestLoader.h
+++ b/Source/WebCore/loader/ApplicationManifestLoader.h
@@ -52,7 +52,7 @@
     Optional<ApplicationManifest>& processManifest();
 
 private:
-    void notifyFinished(CachedResource&);
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&);
 
     DocumentLoader& m_documentLoader;
     Optional<ApplicationManifest> m_processedManifest;
diff --git a/Source/WebCore/loader/CrossOriginPreflightChecker.cpp b/Source/WebCore/loader/CrossOriginPreflightChecker.cpp
index fe3461f..fc8b0b8 100644
--- a/Source/WebCore/loader/CrossOriginPreflightChecker.cpp
+++ b/Source/WebCore/loader/CrossOriginPreflightChecker.cpp
@@ -82,7 +82,7 @@
     loader.preflightSuccess(WTFMove(request));
 }
 
-void CrossOriginPreflightChecker::notifyFinished(CachedResource& resource)
+void CrossOriginPreflightChecker::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT_UNUSED(resource, &resource == m_resource);
     if (m_resource->loadFailedOrCanceled()) {
diff --git a/Source/WebCore/loader/CrossOriginPreflightChecker.h b/Source/WebCore/loader/CrossOriginPreflightChecker.h
index 1a7f4e2..2a037cc 100644
--- a/Source/WebCore/loader/CrossOriginPreflightChecker.h
+++ b/Source/WebCore/loader/CrossOriginPreflightChecker.h
@@ -53,7 +53,7 @@
     void setDefersLoading(bool);
 
 private:
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
     void redirectReceived(CachedResource&, ResourceRequest&&, const ResourceResponse&, CompletionHandler<void(ResourceRequest&&)>&&) final;
 
     static void handleLoadingFailure(DocumentThreadableLoader&, unsigned long, const ResourceError&);
diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp
index 9d703fd..77790ce 100644
--- a/Source/WebCore/loader/DocumentLoader.cpp
+++ b/Source/WebCore/loader/DocumentLoader.cpp
@@ -382,7 +382,7 @@
     return isLoadingMainResource() || !m_subresourceLoaders.isEmpty() || !m_plugInStreamLoaders.isEmpty();
 }
 
-void DocumentLoader::notifyFinished(CachedResource& resource)
+void DocumentLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT(isMainThread());
 #if ENABLE(CONTENT_FILTERING)
diff --git a/Source/WebCore/loader/DocumentLoader.h b/Source/WebCore/loader/DocumentLoader.h
index 410341e..2ab657d 100644
--- a/Source/WebCore/loader/DocumentLoader.h
+++ b/Source/WebCore/loader/DocumentLoader.h
@@ -446,7 +446,7 @@
     WEBCORE_EXPORT void redirectReceived(CachedResource&, ResourceRequest&&, const ResourceResponse&, CompletionHandler<void(ResourceRequest&&)>&&) override;
     WEBCORE_EXPORT void responseReceived(CachedResource&, const ResourceResponse&, CompletionHandler<void()>&&) override;
     WEBCORE_EXPORT void dataReceived(CachedResource&, const char* data, int length) override;
-    WEBCORE_EXPORT void notifyFinished(CachedResource&) override;
+    WEBCORE_EXPORT void notifyFinished(CachedResource&, const NetworkLoadMetrics&) override;
 #if USE(QUICK_LOOK)
     WEBCORE_EXPORT void previewResponseReceived(CachedResource&, const ResourceResponse&) override;
 #endif
diff --git a/Source/WebCore/loader/DocumentThreadableLoader.cpp b/Source/WebCore/loader/DocumentThreadableLoader.cpp
index df3d08c..356cf81 100644
--- a/Source/WebCore/loader/DocumentThreadableLoader.cpp
+++ b/Source/WebCore/loader/DocumentThreadableLoader.cpp
@@ -442,7 +442,7 @@
     m_client->didFinishTiming(resourceTiming);
 }
 
-void DocumentThreadableLoader::notifyFinished(CachedResource& resource)
+void DocumentThreadableLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT(m_client);
     ASSERT_UNUSED(resource, &resource == m_resource);
diff --git a/Source/WebCore/loader/DocumentThreadableLoader.h b/Source/WebCore/loader/DocumentThreadableLoader.h
index 8772c13..63c1a9e 100644
--- a/Source/WebCore/loader/DocumentThreadableLoader.h
+++ b/Source/WebCore/loader/DocumentThreadableLoader.h
@@ -86,7 +86,7 @@
         void redirectReceived(CachedResource&, ResourceRequest&&, const ResourceResponse&, CompletionHandler<void(ResourceRequest&&)>&&) override;
         void finishedTimingForWorkerLoad(CachedResource&, const ResourceTiming&) override;
         void finishedTimingForWorkerLoad(const ResourceTiming&);
-        void notifyFinished(CachedResource&) override;
+        void notifyFinished(CachedResource&, const NetworkLoadMetrics&) override;
 
         void didReceiveResponse(unsigned long identifier, const ResourceResponse&);
         void didReceiveData(unsigned long identifier, const char* data, int dataLength);
diff --git a/Source/WebCore/loader/ImageLoader.cpp b/Source/WebCore/loader/ImageLoader.cpp
index c9b4396..75d5fe0 100644
--- a/Source/WebCore/loader/ImageLoader.cpp
+++ b/Source/WebCore/loader/ImageLoader.cpp
@@ -322,7 +322,7 @@
     rejectPromises(m_decodingPromises, message);
 }
 
-void ImageLoader::notifyFinished(CachedResource& resource)
+void ImageLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT(m_failedLoadURL.isEmpty());
     ASSERT_UNUSED(resource, &resource == m_image.get());
diff --git a/Source/WebCore/loader/ImageLoader.h b/Source/WebCore/loader/ImageLoader.h
index cae63a9..2ec0f15 100644
--- a/Source/WebCore/loader/ImageLoader.h
+++ b/Source/WebCore/loader/ImageLoader.h
@@ -82,7 +82,7 @@
 
 protected:
     explicit ImageLoader(Element&);
-    void notifyFinished(CachedResource&) override;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) override;
 
 private:
     enum class LazyImageLoadState : uint8_t { None, Deferred, LoadImmediately, FullImage };
diff --git a/Source/WebCore/loader/LinkLoader.cpp b/Source/WebCore/loader/LinkLoader.cpp
index 575b9a8..9d66afd 100644
--- a/Source/WebCore/loader/LinkLoader.cpp
+++ b/Source/WebCore/loader/LinkLoader.cpp
@@ -82,7 +82,7 @@
         m_client.linkLoaded();
 }
 
-void LinkLoader::notifyFinished(CachedResource& resource)
+void LinkLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT_UNUSED(resource, m_cachedLinkResource.get() == &resource);
 
diff --git a/Source/WebCore/loader/LinkLoader.h b/Source/WebCore/loader/LinkLoader.h
index b5c7e36..88a2455 100644
--- a/Source/WebCore/loader/LinkLoader.h
+++ b/Source/WebCore/loader/LinkLoader.h
@@ -71,7 +71,7 @@
     void cancelLoad();
 
 private:
-    void notifyFinished(CachedResource&) override;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) override;
     static void preconnectIfNeeded(const LinkLoadParameters&, Document&);
     static std::unique_ptr<LinkPreloadResourceClient> preloadIfNeeded(const LinkLoadParameters&, Document&, LinkLoader*);
     void prefetchIfNeeded(const LinkLoadParameters&, Document&);
diff --git a/Source/WebCore/loader/LinkPreloadResourceClients.h b/Source/WebCore/loader/LinkPreloadResourceClients.h
index 2ec8166..bdd4eeb 100644
--- a/Source/WebCore/loader/LinkPreloadResourceClients.h
+++ b/Source/WebCore/loader/LinkPreloadResourceClients.h
@@ -86,7 +86,7 @@
     }
 
 private:
-    void notifyFinished(CachedResource& resource) final { triggerEvents(resource); }
+    void notifyFinished(CachedResource& resource, const NetworkLoadMetrics&) final { triggerEvents(resource); }
     void clear() final { clearResource(*this); }
     bool shouldMarkAsReferenced() const final { return false; }
 };
@@ -122,7 +122,7 @@
     }
 
 private:
-    void notifyFinished(CachedResource& resource) final { triggerEvents(resource); }
+    void notifyFinished(CachedResource& resource, const NetworkLoadMetrics&) final { triggerEvents(resource); }
     void clear() final { clearResource(*this); }
     bool shouldMarkAsReferenced() const final { return false; }
 };
@@ -157,7 +157,7 @@
     }
 
 private:
-    void notifyFinished(CachedResource& resource) final { triggerEvents(resource); }
+    void notifyFinished(CachedResource& resource, const NetworkLoadMetrics&) final { triggerEvents(resource); }
     void clear() final { clearResource(*this); }
     bool shouldMarkAsReferenced() const final { return false; }
 };
diff --git a/Source/WebCore/loader/MediaResourceLoader.cpp b/Source/WebCore/loader/MediaResourceLoader.cpp
index 64f83d1..859b906 100644
--- a/Source/WebCore/loader/MediaResourceLoader.cpp
+++ b/Source/WebCore/loader/MediaResourceLoader.cpp
@@ -228,7 +228,7 @@
         m_client->dataReceived(*this, data, dataLength);
 }
 
-void MediaResource::notifyFinished(CachedResource& resource)
+void MediaResource::notifyFinished(CachedResource& resource, const NetworkLoadMetrics& metrics)
 {
     ASSERT_UNUSED(resource, &resource == m_resource);
 
@@ -237,7 +237,7 @@
         if (m_resource->loadFailedOrCanceled())
             m_client->loadFailed(*this, m_resource->resourceError());
         else
-            m_client->loadFinished(*this);
+            m_client->loadFinished(*this, metrics);
     }
     stop();
 }
diff --git a/Source/WebCore/loader/MediaResourceLoader.h b/Source/WebCore/loader/MediaResourceLoader.h
index 609d4fe..5316a64 100644
--- a/Source/WebCore/loader/MediaResourceLoader.h
+++ b/Source/WebCore/loader/MediaResourceLoader.h
@@ -84,7 +84,7 @@
     bool shouldCacheResponse(CachedResource&, const ResourceResponse&) override;
     void dataSent(CachedResource&, unsigned long long, unsigned long long) override;
     void dataReceived(CachedResource&, const char*, int) override;
-    void notifyFinished(CachedResource&) override;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) override;
 
 private:
     MediaResource(MediaResourceLoader&, CachedResourceHandle<CachedRawResource>);
diff --git a/Source/WebCore/loader/SubresourceLoader.cpp b/Source/WebCore/loader/SubresourceLoader.cpp
index be6a3fc..499b6a4 100644
--- a/Source/WebCore/loader/SubresourceLoader.cpp
+++ b/Source/WebCore/loader/SubresourceLoader.cpp
@@ -464,7 +464,7 @@
         auto* buffer = resourceData();
         if (m_loadingMultipartContent && buffer && buffer->size()) {
             // The resource data will change as the next part is loaded, so we need to make a copy.
-            m_resource->finishLoading(buffer->copy().ptr());
+            m_resource->finishLoading(buffer->copy().ptr(), { });
             clearResourceData();
             // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once.
             // After the first multipart section is complete, signal to delegates that this load is "finished"
@@ -727,7 +727,7 @@
         tracePoint(SubresourceLoadDidEnd);
 
     m_state = Finishing;
-    m_resource->finishLoading(resourceData());
+    m_resource->finishLoading(resourceData(), networkLoadMetrics);
 
     if (wasCancelled()) {
         RELEASE_LOG_IF_ALLOWED("didFinishLoading: was canceled");
diff --git a/Source/WebCore/loader/TextTrackLoader.cpp b/Source/WebCore/loader/TextTrackLoader.cpp
index 9737474..76a4e97 100644
--- a/Source/WebCore/loader/TextTrackLoader.cpp
+++ b/Source/WebCore/loader/TextTrackLoader.cpp
@@ -116,7 +116,7 @@
     m_state = Failed;
 }
 
-void TextTrackLoader::notifyFinished(CachedResource& resource)
+void TextTrackLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT_UNUSED(resource, m_resource == &resource);
 
diff --git a/Source/WebCore/loader/TextTrackLoader.h b/Source/WebCore/loader/TextTrackLoader.h
index 5d8949e..a8648e4 100644
--- a/Source/WebCore/loader/TextTrackLoader.h
+++ b/Source/WebCore/loader/TextTrackLoader.h
@@ -67,7 +67,7 @@
 
 private:
     // CachedResourceClient
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
     void deprecatedDidReceiveCachedResource(CachedResource&) final;
 
     // WebVTTParserClient
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheResourceLoader.cpp b/Source/WebCore/loader/appcache/ApplicationCacheResourceLoader.cpp
index 588c057..d386045 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheResourceLoader.cpp
+++ b/Source/WebCore/loader/appcache/ApplicationCacheResourceLoader.cpp
@@ -87,7 +87,7 @@
     }
 
     if (response.httpStatusCode() == 304) {
-        notifyFinished(*m_resource);
+        notifyFinished(*m_resource, { });
         return;
     }
 
@@ -117,7 +117,7 @@
     callback(WTFMove(newRequest));
 }
 
-void ApplicationCacheResourceLoader::notifyFinished(CachedResource& resource)
+void ApplicationCacheResourceLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     auto protectedThis = makeRef(*this);
 
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheResourceLoader.h b/Source/WebCore/loader/appcache/ApplicationCacheResourceLoader.h
index 6d9a2da..3e51fd8 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheResourceLoader.h
+++ b/Source/WebCore/loader/appcache/ApplicationCacheResourceLoader.h
@@ -58,7 +58,7 @@
     void responseReceived(CachedResource&, const ResourceResponse&, CompletionHandler<void()>&&) final;
     void dataReceived(CachedResource&, const char* data, int dataLength) final;
     void redirectReceived(CachedResource&, ResourceRequest&&, const ResourceResponse&, CompletionHandler<void(ResourceRequest&&)>&&) final;
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
 
     unsigned m_type;
     CachedResourceHandle<CachedRawResource> m_resource;
diff --git a/Source/WebCore/loader/cache/CachedApplicationManifest.cpp b/Source/WebCore/loader/cache/CachedApplicationManifest.cpp
index dec6a12..02b9ed2 100644
--- a/Source/WebCore/loader/cache/CachedApplicationManifest.cpp
+++ b/Source/WebCore/loader/cache/CachedApplicationManifest.cpp
@@ -40,13 +40,13 @@
 {
 }
 
-void CachedApplicationManifest::finishLoading(SharedBuffer* data)
+void CachedApplicationManifest::finishLoading(SharedBuffer* data, const NetworkLoadMetrics& metrics)
 {
     m_data = data;
     setEncodedSize(data ? data->size() : 0);
     if (data)
         m_text = m_decoder->decodeAndFlush(data->data(), data->size());
-    CachedResource::finishLoading(data);
+    CachedResource::finishLoading(data, metrics);
 }
 
 void CachedApplicationManifest::setEncoding(const String& chs)
diff --git a/Source/WebCore/loader/cache/CachedApplicationManifest.h b/Source/WebCore/loader/cache/CachedApplicationManifest.h
index 83e819a..5eac10e 100644
--- a/Source/WebCore/loader/cache/CachedApplicationManifest.h
+++ b/Source/WebCore/loader/cache/CachedApplicationManifest.h
@@ -43,7 +43,7 @@
     Optional<struct ApplicationManifest> process(const URL& manifestURL, const URL& documentURL, RefPtr<ScriptExecutionContext> = nullptr);
 
 private:
-    void finishLoading(SharedBuffer*) override;
+    void finishLoading(SharedBuffer*, const NetworkLoadMetrics&) override;
     const TextResourceDecoder* textResourceDecoder() const override { return m_decoder.ptr(); }
     void setEncoding(const String&) override;
     String encoding() const override;
diff --git a/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp b/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp
index 2100b33..8e8edbb 100644
--- a/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp
+++ b/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp
@@ -97,7 +97,7 @@
         saveParsedStyleSheet(*sheet.m_parsedStyleSheetCache);
 }
 
-void CachedCSSStyleSheet::finishLoading(SharedBuffer* data)
+void CachedCSSStyleSheet::finishLoading(SharedBuffer* data, const NetworkLoadMetrics& metrics)
 {
     m_data = data;
     setEncodedSize(data ? data->size() : 0);
@@ -105,12 +105,12 @@
     if (data)
         m_decodedSheetText = m_decoder->decodeAndFlush(data->data(), data->size());
     setLoading(false);
-    checkNotify();
+    checkNotify(metrics);
     // Clear the decoded text as it is unlikely to be needed immediately again and is cheap to regenerate.
     m_decodedSheetText = String();
 }
 
-void CachedCSSStyleSheet::checkNotify()
+void CachedCSSStyleSheet::checkNotify(const NetworkLoadMetrics&)
 {
     if (isLoading())
         return;
diff --git a/Source/WebCore/loader/cache/CachedCSSStyleSheet.h b/Source/WebCore/loader/cache/CachedCSSStyleSheet.h
index ad30f81..49d8d54 100644
--- a/Source/WebCore/loader/cache/CachedCSSStyleSheet.h
+++ b/Source/WebCore/loader/cache/CachedCSSStyleSheet.h
@@ -55,12 +55,12 @@
     void setEncoding(const String&) final;
     String encoding() const final;
     const TextResourceDecoder* textResourceDecoder() const final { return m_decoder.get(); }
-    void finishLoading(SharedBuffer*) final;
+    void finishLoading(SharedBuffer*, const NetworkLoadMetrics&) final;
     void destroyDecodedData() final;
 
     void setBodyDataFrom(const CachedResource&) final;
 
-    void checkNotify() final;
+    void checkNotify(const NetworkLoadMetrics&) final;
 
     RefPtr<TextResourceDecoder> m_decoder;
     String m_decodedSheetText;
diff --git a/Source/WebCore/loader/cache/CachedFont.cpp b/Source/WebCore/loader/cache/CachedFont.cpp
index cd949e7..97419ee 100644
--- a/Source/WebCore/loader/cache/CachedFont.cpp
+++ b/Source/WebCore/loader/cache/CachedFont.cpp
@@ -63,12 +63,12 @@
         static_cast<CachedFontClient&>(client).fontLoaded(*this);
 }
 
-void CachedFont::finishLoading(SharedBuffer* data)
+void CachedFont::finishLoading(SharedBuffer* data, const NetworkLoadMetrics& metrics)
 {
     m_data = data;
     setEncodedSize(m_data.get() ? m_data->size() : 0);
     setLoading(false);
-    checkNotify();
+    checkNotify(metrics);
 }
 
 void CachedFont::beginLoadIfNeeded(CachedResourceLoader& loader)
@@ -142,7 +142,7 @@
     m_fontCustomPlatformData = nullptr;
 }
 
-void CachedFont::checkNotify()
+void CachedFont::checkNotify(const NetworkLoadMetrics&)
 {
     if (isLoading())
         return;
diff --git a/Source/WebCore/loader/cache/CachedFont.h b/Source/WebCore/loader/cache/CachedFont.h
index 14572e1..6267788 100644
--- a/Source/WebCore/loader/cache/CachedFont.h
+++ b/Source/WebCore/loader/cache/CachedFont.h
@@ -65,14 +65,14 @@
 private:
     String calculateItemInCollection() const;
 
-    void checkNotify() override;
+    void checkNotify(const NetworkLoadMetrics&) override;
     bool mayTryReplaceEncodedData() const override;
 
     void load(CachedResourceLoader&) override;
     NO_RETURN_DUE_TO_ASSERT void setBodyDataFrom(const CachedResource&) final { ASSERT_NOT_REACHED(); }
 
     void didAddClient(CachedResourceClient&) override;
-    void finishLoading(SharedBuffer*) override;
+    void finishLoading(SharedBuffer*, const NetworkLoadMetrics&) override;
 
     void allClientsRemoved() override;
 
diff --git a/Source/WebCore/loader/cache/CachedImage.cpp b/Source/WebCore/loader/cache/CachedImage.cpp
index cb223ac..c02b665 100644
--- a/Source/WebCore/loader/cache/CachedImage.cpp
+++ b/Source/WebCore/loader/cache/CachedImage.cpp
@@ -565,7 +565,7 @@
     CachedResource::updateData(data, length);
 }
 
-void CachedImage::finishLoading(SharedBuffer* data)
+void CachedImage::finishLoading(SharedBuffer* data, const NetworkLoadMetrics& metrics)
 {
     m_data = convertedDataIfNeeded(data);
     if (m_data) {
@@ -584,7 +584,7 @@
     }
 
     notifyObservers();
-    CachedResource::finishLoading(data);
+    CachedResource::finishLoading(data, metrics);
 }
 
 void CachedImage::didReplaceSharedBufferContents()
diff --git a/Source/WebCore/loader/cache/CachedImage.h b/Source/WebCore/loader/cache/CachedImage.h
index 2be700d..5824249 100644
--- a/Source/WebCore/loader/cache/CachedImage.h
+++ b/Source/WebCore/loader/cache/CachedImage.h
@@ -70,7 +70,7 @@
     bool imageHasRelativeHeight() const { return m_image && m_image->hasRelativeHeight(); }
 
     void updateBuffer(SharedBuffer&) override;
-    void finishLoading(SharedBuffer*) override;
+    void finishLoading(SharedBuffer*, const NetworkLoadMetrics&) override;
 
     enum SizeType {
         UsedSize,
diff --git a/Source/WebCore/loader/cache/CachedRawResource.cpp b/Source/WebCore/loader/cache/CachedRawResource.cpp
index 00a7f23..0197ed8 100644
--- a/Source/WebCore/loader/cache/CachedRawResource.cpp
+++ b/Source/WebCore/loader/cache/CachedRawResource.cpp
@@ -86,7 +86,7 @@
 
     if (m_delayedFinishLoading) {
         auto delayedFinishLoading = std::exchange(m_delayedFinishLoading, WTF::nullopt);
-        finishLoading(delayedFinishLoading->buffer.get());
+        finishLoading(delayedFinishLoading->buffer.get(), { });
     }
 }
 
@@ -97,7 +97,7 @@
     CachedResource::updateData(data, length);
 }
 
-void CachedRawResource::finishLoading(SharedBuffer* data)
+void CachedRawResource::finishLoading(SharedBuffer* data, const NetworkLoadMetrics& metrics)
 {
     if (m_inIncrementalDataNotify) {
         // We may get here synchronously from updateBuffer() if the callback there ends up spinning a runloop.
@@ -120,7 +120,7 @@
     m_allowEncodedDataReplacement = m_loader && !m_loader->isQuickLookResource();
 #endif
 
-    CachedResource::finishLoading(data);
+    CachedResource::finishLoading(data, metrics);
     if (dataBufferingPolicy == DataBufferingPolicy::BufferData && this->dataBufferingPolicy() == DataBufferingPolicy::DoNotBufferData) {
         if (m_loader)
             m_loader->setDataBufferingPolicy(DataBufferingPolicy::DoNotBufferData);
diff --git a/Source/WebCore/loader/cache/CachedRawResource.h b/Source/WebCore/loader/cache/CachedRawResource.h
index 27cddd3..6a6c47b 100644
--- a/Source/WebCore/loader/cache/CachedRawResource.h
+++ b/Source/WebCore/loader/cache/CachedRawResource.h
@@ -53,7 +53,7 @@
     void didAddClient(CachedResourceClient&) final;
     void updateBuffer(SharedBuffer&) final;
     void updateData(const char* data, unsigned length) final;
-    void finishLoading(SharedBuffer*) final;
+    void finishLoading(SharedBuffer*, const NetworkLoadMetrics&) final;
 
     bool shouldIgnoreHTTPStatusCodeErrors() const override { return true; }
     void allClientsRemoved() override;
diff --git a/Source/WebCore/loader/cache/CachedResource.cpp b/Source/WebCore/loader/cache/CachedResource.cpp
index 99b2352..79bd862 100644
--- a/Source/WebCore/loader/cache/CachedResource.cpp
+++ b/Source/WebCore/loader/cache/CachedResource.cpp
@@ -319,7 +319,7 @@
                 InspectorInstrumentation::didFailLoading(protectedFrame.ptr(), protectedFrame->loader().activeDocumentLoader(), identifier, error);
                 return;
             }
-            finishLoading(nullptr);
+            finishLoading(nullptr, { });
             NetworkLoadMetrics emptyMetrics;
             InspectorInstrumentation::didFinishLoading(protectedFrame.ptr(), protectedFrame->loader().activeDocumentLoader(), identifier, emptyMetrics, nullptr);
         });
@@ -366,14 +366,14 @@
     setEncodedSize(resource.encodedSize());
 }
 
-void CachedResource::checkNotify()
+void CachedResource::checkNotify(const NetworkLoadMetrics& metrics)
 {
     if (isLoading() || stillNeedsLoad())
         return;
 
     CachedResourceClientWalker<CachedResourceClient> walker(m_clients);
     while (CachedResourceClient* client = walker.next())
-        client->notifyFinished(*this);
+        client->notifyFinished(*this, metrics);
 }
 
 void CachedResource::updateBuffer(SharedBuffer&)
@@ -386,10 +386,10 @@
     ASSERT(dataBufferingPolicy() == DataBufferingPolicy::DoNotBufferData);
 }
 
-void CachedResource::finishLoading(SharedBuffer*)
+void CachedResource::finishLoading(SharedBuffer*, const NetworkLoadMetrics& metrics)
 {
     setLoading(false);
-    checkNotify();
+    checkNotify(metrics);
 }
 
 void CachedResource::error(CachedResource::Status status)
@@ -399,7 +399,7 @@
     m_data = nullptr;
 
     setLoading(false);
-    checkNotify();
+    checkNotify({ });
 }
     
 void CachedResource::cancelLoad()
@@ -414,7 +414,7 @@
         setStatus(LoadError);
 
     setLoading(false);
-    checkNotify();
+    checkNotify({ });
 }
 
 void CachedResource::finish()
@@ -549,7 +549,7 @@
 
     // FIXME: Make calls to notifyFinished async
     if (!isLoading() && !stillNeedsLoad())
-        client.notifyFinished(*this);
+        client.notifyFinished(*this, { });
 }
 
 bool CachedResource::addClientToSet(CachedResourceClient& client)
diff --git a/Source/WebCore/loader/cache/CachedResource.h b/Source/WebCore/loader/cache/CachedResource.h
index 9cdc1bc..6f314f1 100644
--- a/Source/WebCore/loader/cache/CachedResource.h
+++ b/Source/WebCore/loader/cache/CachedResource.h
@@ -48,6 +48,7 @@
 class CookieJar;
 class LoadTiming;
 class MemoryCache;
+class NetworkLoadMetrics;
 class SecurityOrigin;
 class SharedBuffer;
 class SubresourceLoader;
@@ -113,7 +114,7 @@
     virtual const TextResourceDecoder* textResourceDecoder() const { return nullptr; }
     virtual void updateBuffer(SharedBuffer&);
     virtual void updateData(const char* data, unsigned length);
-    virtual void finishLoading(SharedBuffer*);
+    virtual void finishLoading(SharedBuffer*, const NetworkLoadMetrics&);
     virtual void error(CachedResource::Status);
 
     void setResourceError(const ResourceError& error) { m_error = error; }
@@ -314,7 +315,7 @@
 
     void decodedDataDeletionTimerFired();
 
-    virtual void checkNotify();
+    virtual void checkNotify(const NetworkLoadMetrics&);
     virtual bool mayTryReplaceEncodedData() const { return false; }
 
     Seconds freshnessLifetime(const ResourceResponse&) const;
diff --git a/Source/WebCore/loader/cache/CachedResourceClient.h b/Source/WebCore/loader/cache/CachedResourceClient.h
index 793677d..9df454a9 100644
--- a/Source/WebCore/loader/cache/CachedResourceClient.h
+++ b/Source/WebCore/loader/cache/CachedResourceClient.h
@@ -26,6 +26,7 @@
 namespace WebCore {
 
 class CachedResource;
+class NetworkLoadMetrics;
 
 class CachedResourceClient {
 public:
@@ -39,7 +40,7 @@
     };
 
     virtual ~CachedResourceClient() = default;
-    virtual void notifyFinished(CachedResource&) { }
+    virtual void notifyFinished(CachedResource&, const NetworkLoadMetrics&) { }
     virtual void deprecatedDidReceiveCachedResource(CachedResource&) { }
 
     static CachedResourceClientType expectedType() { return BaseResourceType; }
diff --git a/Source/WebCore/loader/cache/CachedSVGDocument.cpp b/Source/WebCore/loader/cache/CachedSVGDocument.cpp
index 7982707..b53f753 100644
--- a/Source/WebCore/loader/cache/CachedSVGDocument.cpp
+++ b/Source/WebCore/loader/cache/CachedSVGDocument.cpp
@@ -45,14 +45,14 @@
     return m_decoder->encoding().name();
 }
 
-void CachedSVGDocument::finishLoading(SharedBuffer* data)
+void CachedSVGDocument::finishLoading(SharedBuffer* data, const NetworkLoadMetrics& metrics)
 {
     if (data) {
         // We don't need to create a new frame because the new document belongs to the parent UseElement.
         m_document = SVGDocument::create(nullptr, response().url());
         m_document->setContent(m_decoder->decodeAndFlush(data->data(), data->size()));
     }
-    CachedResource::finishLoading(data);
+    CachedResource::finishLoading(data, metrics);
 }
 
 }
diff --git a/Source/WebCore/loader/cache/CachedSVGDocument.h b/Source/WebCore/loader/cache/CachedSVGDocument.h
index 7447aa2..9e60761 100644
--- a/Source/WebCore/loader/cache/CachedSVGDocument.h
+++ b/Source/WebCore/loader/cache/CachedSVGDocument.h
@@ -40,7 +40,7 @@
     void setEncoding(const String&) override;
     String encoding() const override;
     const TextResourceDecoder* textResourceDecoder() const override { return m_decoder.get(); }
-    void finishLoading(SharedBuffer*) override;
+    void finishLoading(SharedBuffer*, const NetworkLoadMetrics&) override;
 
     RefPtr<SVGDocument> m_document;
     RefPtr<TextResourceDecoder> m_decoder;
diff --git a/Source/WebCore/loader/cache/CachedScript.cpp b/Source/WebCore/loader/cache/CachedScript.cpp
index 708a398..1746a38 100644
--- a/Source/WebCore/loader/cache/CachedScript.cpp
+++ b/Source/WebCore/loader/cache/CachedScript.cpp
@@ -96,11 +96,11 @@
     return m_scriptHash;
 }
 
-void CachedScript::finishLoading(SharedBuffer* data)
+void CachedScript::finishLoading(SharedBuffer* data, const NetworkLoadMetrics& metrics)
 {
     m_data = data;
     setEncodedSize(data ? data->size() : 0);
-    CachedResource::finishLoading(data);
+    CachedResource::finishLoading(data, metrics);
 }
 
 void CachedScript::destroyDecodedData()
diff --git a/Source/WebCore/loader/cache/CachedScript.h b/Source/WebCore/loader/cache/CachedScript.h
index dd6fbcc..543a918 100644
--- a/Source/WebCore/loader/cache/CachedScript.h
+++ b/Source/WebCore/loader/cache/CachedScript.h
@@ -47,7 +47,7 @@
     void setEncoding(const String&) final;
     String encoding() const final;
     const TextResourceDecoder* textResourceDecoder() const final { return m_decoder.get(); }
-    void finishLoading(SharedBuffer*) final;
+    void finishLoading(SharedBuffer*, const NetworkLoadMetrics&) final;
 
     void destroyDecodedData() final;
 
diff --git a/Source/WebCore/loader/cache/CachedTextTrack.cpp b/Source/WebCore/loader/cache/CachedTextTrack.cpp
index c6e20e7..0507c01 100644
--- a/Source/WebCore/loader/cache/CachedTextTrack.cpp
+++ b/Source/WebCore/loader/cache/CachedTextTrack.cpp
@@ -59,10 +59,10 @@
     CachedResource::updateBuffer(data);
 }
 
-void CachedTextTrack::finishLoading(SharedBuffer* data)
+void CachedTextTrack::finishLoading(SharedBuffer* data, const NetworkLoadMetrics& metrics)
 {
     doUpdateBuffer(data);
-    CachedResource::finishLoading(data);
+    CachedResource::finishLoading(data, metrics);
 }
 
 }
diff --git a/Source/WebCore/loader/cache/CachedTextTrack.h b/Source/WebCore/loader/cache/CachedTextTrack.h
index 044d54c..d5f42b2 100644
--- a/Source/WebCore/loader/cache/CachedTextTrack.h
+++ b/Source/WebCore/loader/cache/CachedTextTrack.h
@@ -38,7 +38,7 @@
 private:
     bool mayTryReplaceEncodedData() const override { return true; }
     void updateBuffer(SharedBuffer&) override;
-    void finishLoading(SharedBuffer*) override;
+    void finishLoading(SharedBuffer*, const NetworkLoadMetrics&) override;
 
     void doUpdateBuffer(SharedBuffer*);
 };
diff --git a/Source/WebCore/loader/cache/CachedXSLStyleSheet.cpp b/Source/WebCore/loader/cache/CachedXSLStyleSheet.cpp
index f7a8378..648111c 100644
--- a/Source/WebCore/loader/cache/CachedXSLStyleSheet.cpp
+++ b/Source/WebCore/loader/cache/CachedXSLStyleSheet.cpp
@@ -61,17 +61,17 @@
     return m_decoder->encoding().name();
 }
 
-void CachedXSLStyleSheet::finishLoading(SharedBuffer* data)
+void CachedXSLStyleSheet::finishLoading(SharedBuffer* data, const NetworkLoadMetrics& metrics)
 {
     m_data = data;
     setEncodedSize(data ? data->size() : 0);
     if (data)
         m_sheet = m_decoder->decodeAndFlush(data->data(), encodedSize());
     setLoading(false);
-    checkNotify();
+    checkNotify(metrics);
 }
 
-void CachedXSLStyleSheet::checkNotify()
+void CachedXSLStyleSheet::checkNotify(const NetworkLoadMetrics&)
 {
     if (isLoading())
         return;
diff --git a/Source/WebCore/loader/cache/CachedXSLStyleSheet.h b/Source/WebCore/loader/cache/CachedXSLStyleSheet.h
index 5eddbaf..3779aa6 100644
--- a/Source/WebCore/loader/cache/CachedXSLStyleSheet.h
+++ b/Source/WebCore/loader/cache/CachedXSLStyleSheet.h
@@ -41,13 +41,13 @@
     const String& sheet() const { return m_sheet; }
 
 private:
-    void checkNotify() final;
+    void checkNotify(const NetworkLoadMetrics&) final;
     bool mayTryReplaceEncodedData() const final { return true; }
     void didAddClient(CachedResourceClient&) final;
     void setEncoding(const String&) final;
     String encoding() const final;
     const TextResourceDecoder* textResourceDecoder() const final { return m_decoder.get(); }
-    void finishLoading(SharedBuffer*) final;
+    void finishLoading(SharedBuffer*, const NetworkLoadMetrics&) final;
 
     String m_sheet;
     RefPtr<TextResourceDecoder> m_decoder;
diff --git a/Source/WebCore/loader/cache/KeepaliveRequestTracker.cpp b/Source/WebCore/loader/cache/KeepaliveRequestTracker.cpp
index 00c5505..66f7e89 100644
--- a/Source/WebCore/loader/cache/KeepaliveRequestTracker.cpp
+++ b/Source/WebCore/loader/cache/KeepaliveRequestTracker.cpp
@@ -76,7 +76,7 @@
         completionHandler();
 }
 
-void KeepaliveRequestTracker::notifyFinished(CachedResource& resource)
+void KeepaliveRequestTracker::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     unregisterRequest(resource);
 }
diff --git a/Source/WebCore/loader/cache/KeepaliveRequestTracker.h b/Source/WebCore/loader/cache/KeepaliveRequestTracker.h
index 0c333db..7b46bb3 100644
--- a/Source/WebCore/loader/cache/KeepaliveRequestTracker.h
+++ b/Source/WebCore/loader/cache/KeepaliveRequestTracker.h
@@ -39,7 +39,7 @@
 
     // CachedRawResourceClient.
     void responseReceived(CachedResource&, const ResourceResponse&, CompletionHandler<void()>&&) final;
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
 
 private:
     void registerRequest(CachedResource&);
diff --git a/Source/WebCore/loader/icon/IconLoader.cpp b/Source/WebCore/loader/icon/IconLoader.cpp
index 1195c28..2361a4b 100644
--- a/Source/WebCore/loader/icon/IconLoader.cpp
+++ b/Source/WebCore/loader/icon/IconLoader.cpp
@@ -104,7 +104,7 @@
     }
 }
 
-void IconLoader::notifyFinished(CachedResource& resource)
+void IconLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT_UNUSED(resource, &resource == m_resource);
 
diff --git a/Source/WebCore/loader/icon/IconLoader.h b/Source/WebCore/loader/icon/IconLoader.h
index 34a0f32..4b4bbbb 100644
--- a/Source/WebCore/loader/icon/IconLoader.h
+++ b/Source/WebCore/loader/icon/IconLoader.h
@@ -47,7 +47,7 @@
     void stopLoading();
 
 private:
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
 
     DocumentLoader& m_documentLoader;
     URL m_url;
diff --git a/Source/WebCore/platform/graphics/PlatformMediaResourceLoader.h b/Source/WebCore/platform/graphics/PlatformMediaResourceLoader.h
index 4839e8f..7d5b382 100644
--- a/Source/WebCore/platform/graphics/PlatformMediaResourceLoader.h
+++ b/Source/WebCore/platform/graphics/PlatformMediaResourceLoader.h
@@ -51,7 +51,7 @@
     virtual void dataReceived(PlatformMediaResource&, const char*, int) { }
     virtual void accessControlCheckFailed(PlatformMediaResource&, const ResourceError&) { }
     virtual void loadFailed(PlatformMediaResource&, const ResourceError&) { }
-    virtual void loadFinished(PlatformMediaResource&) { }
+    virtual void loadFinished(PlatformMediaResource&, const NetworkLoadMetrics&) { }
 };
 
 class PlatformMediaResourceLoader : public ThreadSafeRefCounted<PlatformMediaResourceLoader, WTF::DestructionThread::Main> {
diff --git a/Source/WebCore/platform/graphics/avfoundation/cf/WebCoreAVCFResourceLoader.cpp b/Source/WebCore/platform/graphics/avfoundation/cf/WebCoreAVCFResourceLoader.cpp
index 1656458..8a014dc 100644
--- a/Source/WebCore/platform/graphics/avfoundation/cf/WebCoreAVCFResourceLoader.cpp
+++ b/Source/WebCore/platform/graphics/avfoundation/cf/WebCoreAVCFResourceLoader.cpp
@@ -143,7 +143,7 @@
     fulfillRequestWithResource(resource);
 }
 
-void WebCoreAVCFResourceLoader::notifyFinished(CachedResource& resource)
+void WebCoreAVCFResourceLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     if (resource.loadFailedOrCanceled()) {
         // <rdar://problem/13987417> Set the contentType of the contentInformationRequest to an empty
diff --git a/Source/WebCore/platform/graphics/avfoundation/cf/WebCoreAVCFResourceLoader.h b/Source/WebCore/platform/graphics/avfoundation/cf/WebCoreAVCFResourceLoader.h
index 1135bbb..0fce0ea 100644
--- a/Source/WebCore/platform/graphics/avfoundation/cf/WebCoreAVCFResourceLoader.h
+++ b/Source/WebCore/platform/graphics/avfoundation/cf/WebCoreAVCFResourceLoader.h
@@ -58,7 +58,7 @@
     // CachedRawResourceClient
     void responseReceived(CachedResource&, const ResourceResponse&, CompletionHandler<void()>&&) override;
     void dataReceived(CachedResource&, const char*, int) override;
-    void notifyFinished(CachedResource&) override;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) override;
 
     void fulfillRequestWithResource(CachedResource&);
 
diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/WebCoreAVFResourceLoader.mm b/Source/WebCore/platform/graphics/avfoundation/objc/WebCoreAVFResourceLoader.mm
index d5f0f78..fba80d1 100644
--- a/Source/WebCore/platform/graphics/avfoundation/objc/WebCoreAVFResourceLoader.mm
+++ b/Source/WebCore/platform/graphics/avfoundation/objc/WebCoreAVFResourceLoader.mm
@@ -56,7 +56,7 @@
     // CachedRawResourceClient
     void responseReceived(CachedResource&, const ResourceResponse&, CompletionHandler<void()>&&) final;
     void dataReceived(CachedResource&, const char*, int) final;
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
 
     void fulfillRequestWithResource(CachedResource&);
 
@@ -112,7 +112,7 @@
     m_parent.responseReceived(response);
 }
 
-void CachedResourceMediaLoader::notifyFinished(CachedResource& resource)
+void CachedResourceMediaLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     if (resource.loadFailedOrCanceled()) {
         m_parent.loadFailed(resource.resourceError());
@@ -150,7 +150,7 @@
     void dataReceived(PlatformMediaResource&, const char*, int) final;
     void accessControlCheckFailed(PlatformMediaResource&, const ResourceError& error) final { loadFailed(error); }
     void loadFailed(PlatformMediaResource&, const ResourceError& error) final { loadFailed(error); }
-    void loadFinished(PlatformMediaResource&) final { loadFinished(); }
+    void loadFinished(PlatformMediaResource&, const NetworkLoadMetrics&) final { loadFinished(); }
 
     WebCoreAVFResourceLoader& m_parent;
     RefPtr<PlatformMediaResource> m_resource;
diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp
index 00f6a8f..85dc8d4 100644
--- a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp
+++ b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp
@@ -72,7 +72,7 @@
     void dataReceived(PlatformMediaResource&, const char*, int) override;
     void accessControlCheckFailed(PlatformMediaResource&, const ResourceError&) override;
     void loadFailed(PlatformMediaResource&, const ResourceError&) override;
-    void loadFinished(PlatformMediaResource&) override;
+    void loadFinished(PlatformMediaResource&, const NetworkLoadMetrics&) override;
 
     static constexpr int s_growBlocksizeLimit { 1 };
     static constexpr int s_growBlocksizeCount { 2 };
@@ -1170,7 +1170,7 @@
     members->responseCondition.notifyOne();
 }
 
-void CachedResourceStreamingClient::loadFinished(PlatformMediaResource&)
+void CachedResourceStreamingClient::loadFinished(PlatformMediaResource&, const NetworkLoadMetrics&)
 {
     ASSERT(isMainThread());
     WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
diff --git a/Source/WebCore/platform/network/NetworkLoadMetrics.h b/Source/WebCore/platform/network/NetworkLoadMetrics.h
index f8979dc..d69ebdd 100644
--- a/Source/WebCore/platform/network/NetworkLoadMetrics.h
+++ b/Source/WebCore/platform/network/NetworkLoadMetrics.h
@@ -54,7 +54,9 @@
     bool isComplete() const { return complete; }
     void markComplete() { complete = true; }
 
-    // These should be treated as deltas to LoadTiming's fetchStart.
+    Seconds fetchStart;
+
+    // These should be treated as deltas to fetchStart.
     // They should be in ascending order as listed here.
     Seconds domainLookupStart { -1 };     // -1 if no DNS.
     Seconds domainLookupEnd { -1 };       // -1 if no DNS.
@@ -81,6 +83,8 @@
     {
         NetworkLoadMetrics copy;
 
+        copy.fetchStart = fetchStart;
+
         copy.domainLookupStart = domainLookupStart;
         copy.domainLookupEnd = domainLookupEnd;
         copy.connectStart = connectStart;
@@ -110,7 +114,8 @@
 
     bool operator==(const NetworkLoadMetrics& other) const
     {
-        return domainLookupStart == other.domainLookupStart
+        return fetchStart == other.fetchStart
+            && domainLookupStart == other.domainLookupStart
             && domainLookupEnd == other.domainLookupEnd
             && connectStart == other.connectStart
             && secureConnectionStart == other.secureConnectionStart
@@ -165,6 +170,7 @@
 template<class Encoder>
 void NetworkLoadMetrics::encode(Encoder& encoder) const
 {
+    encoder << fetchStart;
     encoder << domainLookupStart;
     encoder << domainLookupEnd;
     encoder << connectStart;
@@ -191,7 +197,8 @@
 template<class Decoder>
 bool NetworkLoadMetrics::decode(Decoder& decoder, NetworkLoadMetrics& metrics)
 {
-    return decoder.decode(metrics.domainLookupStart)
+    return decoder.decode(metrics.fetchStart)
+        && decoder.decode(metrics.domainLookupStart)
         && decoder.decode(metrics.domainLookupEnd)
         && decoder.decode(metrics.connectStart)
         && decoder.decode(metrics.secureConnectionStart)
diff --git a/Source/WebCore/platform/network/cocoa/NetworkLoadMetrics.mm b/Source/WebCore/platform/network/cocoa/NetworkLoadMetrics.mm
index d1e63f9..8a57edc 100644
--- a/Source/WebCore/platform/network/cocoa/NetworkLoadMetrics.mm
+++ b/Source/WebCore/platform/network/cocoa/NetworkLoadMetrics.mm
@@ -56,6 +56,7 @@
     double requestStart = timingValue(timingData, @"_kCFNTimingDataRequestStart");
     double responseStart = timingValue(timingData, @"_kCFNTimingDataResponseStart");
 
+    timing->fetchStart = Seconds(referenceStart);
     timing->domainLookupStart = Seconds(domainLookupStart <= 0 ? -1 : domainLookupStart - referenceStart);
     timing->domainLookupEnd = Seconds(domainLookupEnd <= 0 ? -1 : domainLookupEnd - referenceStart);
     timing->connectStart = Seconds(connectStart <= 0 ? -1 : connectStart - referenceStart);
diff --git a/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.mm b/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.mm
index 74ed934..69effbd 100644
--- a/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.mm
+++ b/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.mm
@@ -39,6 +39,121 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
+static NSDate * __nullable networkLoadMetricsDate(Seconds fetchStart, Seconds delta)
+{
+    if (!fetchStart.value())
+        return nil;
+    if (delta.value() == -1)
+        return nil;
+    return [NSDate dateWithTimeIntervalSince1970:fetchStart.value() + delta.value()];
+}
+
+@interface WebCoreNSURLSessionTaskTransactionMetrics : NSObject
+- (instancetype)_initWithMetrics:(const WebCore::NetworkLoadMetrics&)metrics;
+@property (nullable, copy, readonly) NSDate *fetchStartDate;
+@property (nullable, copy, readonly) NSDate *domainLookupStartDate;
+@property (nullable, copy, readonly) NSDate *domainLookupEndDate;
+@property (nullable, copy, readonly) NSDate *connectStartDate;
+@property (nullable, copy, readonly) NSDate *secureConnectionStartDate;
+@property (nullable, copy, readonly) NSDate *connectEndDate;
+@property (nullable, copy, readonly) NSDate *requestStartDate;
+@property (nullable, copy, readonly) NSDate *responseStartDate;
+@property (nullable, copy, readonly) NSDate *responseEndDate;
+@end
+
+@implementation WebCoreNSURLSessionTaskTransactionMetrics {
+    WebCore::NetworkLoadMetrics _metrics;
+}
+
+- (instancetype)_initWithMetrics:(const WebCore::NetworkLoadMetrics&)metrics
+{
+    if (!(self = [super init]))
+        return nil;
+    _metrics = metrics;
+    return self;
+}
+
+@dynamic fetchStartDate;
+- (nullable NSDate *)fetchStartDate
+{
+    return networkLoadMetricsDate(_metrics.fetchStart, Seconds(0));
+}
+
+@dynamic domainLookupStartDate;
+- (nullable NSDate *)domainLookupStartDate
+{
+    return networkLoadMetricsDate(_metrics.fetchStart, _metrics.domainLookupStart);
+}
+
+@dynamic domainLookupEndDate;
+- (nullable NSDate *)domainLookupEndDate
+{
+    return networkLoadMetricsDate(_metrics.fetchStart, _metrics.domainLookupEnd);
+}
+
+@dynamic connectStartDate;
+- (nullable NSDate *)connectStartDate
+{
+    return networkLoadMetricsDate(_metrics.fetchStart, _metrics.connectStart);
+}
+
+@dynamic secureConnectionStartDate;
+- (nullable NSDate *)secureConnectionStartDate
+{
+    return networkLoadMetricsDate(_metrics.fetchStart, _metrics.secureConnectionStart);
+}
+
+@dynamic connectEndDate;
+- (nullable NSDate *)connectEndDate
+{
+    return networkLoadMetricsDate(_metrics.fetchStart, _metrics.connectEnd);
+}
+
+@dynamic requestStartDate;
+- (nullable NSDate *)requestStartDate
+{
+    return networkLoadMetricsDate(_metrics.fetchStart, _metrics.requestStart);
+}
+
+@dynamic responseStartDate;
+- (nullable NSDate *)responseStartDate
+{
+    return networkLoadMetricsDate(_metrics.fetchStart, _metrics.responseStart);
+}
+
+@dynamic responseEndDate;
+- (nullable NSDate *)responseEndDate
+{
+    return networkLoadMetricsDate(_metrics.fetchStart, _metrics.responseEnd);
+}
+
+@end
+
+@interface WebCoreNSURLSessionTaskMetrics : NSObject
+- (instancetype)_initWithMetrics:(const WebCore::NetworkLoadMetrics&)metrics;
+@property (copy, readonly) NSArray<NSURLSessionTaskTransactionMetrics *> *transactionMetrics;
+@end
+
+@implementation WebCoreNSURLSessionTaskMetrics {
+    RetainPtr<WebCoreNSURLSessionTaskTransactionMetrics> _transactionMetrics;
+}
+
+- (instancetype)_initWithMetrics:(const WebCore::NetworkLoadMetrics&)metrics
+{
+    if (!(self = [super init]))
+        return nil;
+    _transactionMetrics = adoptNS([[WebCoreNSURLSessionTaskTransactionMetrics alloc] _initWithMetrics:metrics]);
+    return self;
+}
+
+@dynamic transactionMetrics;
+- (NSArray<NSURLSessionTaskTransactionMetrics *> *)transactionMetrics
+{
+    return @[ (NSURLSessionTaskTransactionMetrics *)self->_transactionMetrics.get() ];
+}
+
+@end
+
 @interface WebCoreNSURLSession ()
 @property (readonly) PlatformMediaResourceLoader& loader;
 @property (readwrite, retain) id<NSURLSessionTaskDelegate> delegate;
@@ -63,7 +178,7 @@
 - (void)resource:(PlatformMediaResource&)resource receivedRedirect:(const ResourceResponse&)response request:(ResourceRequest&&)request completionHandler:(CompletionHandler<void(ResourceRequest&&)>&&)completionHandler;
 - (void)resource:(PlatformMediaResource&)resource accessControlCheckFailedWithError:(const ResourceError&)error;
 - (void)resource:(PlatformMediaResource&)resource loadFailedWithError:(const ResourceError&)error;
-- (void)resourceFinished:(PlatformMediaResource&)resource;
+- (void)resourceFinished:(PlatformMediaResource&)resource metrics:(const NetworkLoadMetrics&)metrics;
 @end
 
 NS_ASSUME_NONNULL_END
@@ -389,7 +504,7 @@
     void dataReceived(PlatformMediaResource&, const char* /* data */, int /* length */) override;
     void accessControlCheckFailed(PlatformMediaResource&, const ResourceError&) override;
     void loadFailed(PlatformMediaResource&, const ResourceError&) override;
-    void loadFinished(PlatformMediaResource&) override;
+    void loadFinished(PlatformMediaResource&, const NetworkLoadMetrics&) override;
 
 private:
     Lock m_taskLock;
@@ -469,13 +584,13 @@
     [m_task resource:resource loadFailedWithError:error];
 }
 
-void WebCoreNSURLSessionDataTaskClient::loadFinished(PlatformMediaResource& resource)
+void WebCoreNSURLSessionDataTaskClient::loadFinished(PlatformMediaResource& resource, const NetworkLoadMetrics& metrics)
 {
     LockHolder locker(m_taskLock);
     if (!m_task)
         return;
 
-    [m_task resourceFinished:resource];
+    [m_task resourceFinished:resource metrics:metrics];
 }
 
 }
@@ -541,7 +656,7 @@
 {
     ASSERT(isMainThread());
     if (_resource)
-        [self resourceFinished:*_resource];
+        [self resourceFinished:*_resource metrics:NetworkLoadMetrics { }];
 }
 
 #pragma mark - NSURLSession API
@@ -719,7 +834,7 @@
     }];
 }
 
-- (void)_resource:(PlatformMediaResource&)resource loadFinishedWithError:(NSError *)error
+- (void)_resource:(PlatformMediaResource&)resource loadFinishedWithError:(NSError *)error metrics:(const NetworkLoadMetrics&)metrics
 {
     ASSERT_UNUSED(resource, &resource == _resource);
     if (self.state == NSURLSessionTaskStateCompleted)
@@ -729,8 +844,12 @@
     RetainPtr<WebCoreNSURLSessionDataTask> strongSelf { self };
     RetainPtr<WebCoreNSURLSession> strongSession { self.session };
     RetainPtr<NSError> strongError { error };
-    [self.session addDelegateOperation:[strongSelf, strongSession, strongError] {
+    [self.session addDelegateOperation:[strongSelf, strongSession, strongError, metrics = metrics.isolatedCopy()] {
         id<NSURLSessionTaskDelegate> delegate = (id<NSURLSessionTaskDelegate>)strongSession.get().delegate;
+
+        if ([delegate respondsToSelector:@selector(URLSession:task:didFinishCollectingMetrics:)])
+            [delegate URLSession:(NSURLSession *)strongSession.get() task:(NSURLSessionDataTask *)strongSelf.get() didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)adoptNS([[WebCoreNSURLSessionTaskMetrics alloc] _initWithMetrics:metrics]).get()];
+
         if ([delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)])
             [delegate URLSession:(NSURLSession *)strongSession.get() task:(NSURLSessionDataTask *)strongSelf.get() didCompleteWithError:strongError.get()];
 
@@ -742,16 +861,16 @@
 
 - (void)resource:(PlatformMediaResource&)resource accessControlCheckFailedWithError:(const ResourceError&)error
 {
-    [self _resource:resource loadFinishedWithError:error.nsError()];
+    [self _resource:resource loadFinishedWithError:error.nsError() metrics:NetworkLoadMetrics { }];
 }
 
 - (void)resource:(PlatformMediaResource&)resource loadFailedWithError:(const ResourceError&)error
 {
-    [self _resource:resource loadFinishedWithError:error.nsError()];
+    [self _resource:resource loadFinishedWithError:error.nsError() metrics:NetworkLoadMetrics { }];
 }
 
-- (void)resourceFinished:(PlatformMediaResource&)resource
+- (void)resourceFinished:(PlatformMediaResource&)resource metrics:(const NetworkLoadMetrics&)metrics
 {
-    [self _resource:resource loadFinishedWithError:nil];
+    [self _resource:resource loadFinishedWithError:nil metrics:metrics];
 }
 @end
diff --git a/Source/WebCore/rendering/RenderElement.cpp b/Source/WebCore/rendering/RenderElement.cpp
index dba89eb..4376091 100644
--- a/Source/WebCore/rendering/RenderElement.cpp
+++ b/Source/WebCore/rendering/RenderElement.cpp
@@ -1326,7 +1326,7 @@
     return isVisible ? VisibleInViewportState::Yes : VisibleInViewportState::No;
 }
 
-void RenderElement::notifyFinished(CachedResource& resource)
+void RenderElement::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     document().cachedResourceLoader().notifyFinished(resource);
 }
diff --git a/Source/WebCore/rendering/RenderElement.h b/Source/WebCore/rendering/RenderElement.h
index 37620e2..a476a74 100644
--- a/Source/WebCore/rendering/RenderElement.h
+++ b/Source/WebCore/rendering/RenderElement.h
@@ -266,7 +266,7 @@
     void insertedIntoTree() override;
     void willBeRemovedFromTree() override;
     void willBeDestroyed() override;
-    void notifyFinished(CachedResource&) override;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) override;
 
     void setRenderInlineAlwaysCreatesLineBoxes(bool b) { m_renderInlineAlwaysCreatesLineBoxes = b; }
     bool renderInlineAlwaysCreatesLineBoxes() const { return m_renderInlineAlwaysCreatesLineBoxes; }
diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp
index f10b1db..993c49c 100644
--- a/Source/WebCore/rendering/RenderImage.cpp
+++ b/Source/WebCore/rendering/RenderImage.cpp
@@ -403,7 +403,7 @@
     contentChanged(ImageChanged);
 }
 
-void RenderImage::notifyFinished(CachedResource& newImage)
+void RenderImage::notifyFinished(CachedResource& newImage, const NetworkLoadMetrics& metrics)
 {
     if (renderTreeBeingDestroyed())
         return;
@@ -419,7 +419,7 @@
     if (is<HTMLImageElement>(element()))
         page().didFinishLoadingImageForElement(downcast<HTMLImageElement>(*element()));
 
-    RenderReplaced::notifyFinished(newImage);
+    RenderReplaced::notifyFinished(newImage, metrics);
 }
 
 void RenderImage::setImageDevicePixelRatio(float factor)
diff --git a/Source/WebCore/rendering/RenderImage.h b/Source/WebCore/rendering/RenderImage.h
index 2b61fae..51b07b0 100644
--- a/Source/WebCore/rendering/RenderImage.h
+++ b/Source/WebCore/rendering/RenderImage.h
@@ -119,7 +119,7 @@
 
     LayoutUnit minimumReplacedHeight() const override;
 
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
     bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) final;
 
     bool boxShadowShouldBeAppliedToBackground(const LayoutPoint& paintOffset, BackgroundBleedAvoidance, InlineFlowBox*) const final;
diff --git a/Source/WebCore/rendering/RenderLayerFilters.cpp b/Source/WebCore/rendering/RenderLayerFilters.cpp
index c081557..250a7d5c 100644
--- a/Source/WebCore/rendering/RenderLayerFilters.cpp
+++ b/Source/WebCore/rendering/RenderLayerFilters.cpp
@@ -65,7 +65,7 @@
     return m_filter && m_filter->hasFilterThatShouldBeRestrictedBySecurityOrigin();
 }
 
-void RenderLayerFilters::notifyFinished(CachedResource&)
+void RenderLayerFilters::notifyFinished(CachedResource&, const NetworkLoadMetrics&)
 {
     // FIXME: This really shouldn't have to invalidate layer composition,
     // but tests like css3/filters/effect-reference-delete.html fail if that doesn't happen.
diff --git a/Source/WebCore/rendering/RenderLayerFilters.h b/Source/WebCore/rendering/RenderLayerFilters.h
index d344cbd..3da140a 100644
--- a/Source/WebCore/rendering/RenderLayerFilters.h
+++ b/Source/WebCore/rendering/RenderLayerFilters.h
@@ -67,7 +67,7 @@
     void applyFilterEffect(GraphicsContext& destinationContext);
 
 private:
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
     void resetDirtySourceRect() { m_dirtySourceRect = LayoutRect(); }
 
     RenderLayer& m_layer;
diff --git a/Source/WebCore/svg/SVGFEImageElement.cpp b/Source/WebCore/svg/SVGFEImageElement.cpp
index 2d59e50..c5c48ef 100644
--- a/Source/WebCore/svg/SVGFEImageElement.cpp
+++ b/Source/WebCore/svg/SVGFEImageElement.cpp
@@ -162,7 +162,7 @@
         clearResourceReferences();
 }
 
-void SVGFEImageElement::notifyFinished(CachedResource&)
+void SVGFEImageElement::notifyFinished(CachedResource&, const NetworkLoadMetrics&)
 {
     if (!isConnected())
         return;
diff --git a/Source/WebCore/svg/SVGFEImageElement.h b/Source/WebCore/svg/SVGFEImageElement.h
index f27dc38..d93e0d0 100644
--- a/Source/WebCore/svg/SVGFEImageElement.h
+++ b/Source/WebCore/svg/SVGFEImageElement.h
@@ -50,7 +50,7 @@
     void parseAttribute(const QualifiedName&, const AtomString&) override;
     void svgAttributeChanged(const QualifiedName&) override;
 
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
     void addSubresourceAttributeURLs(ListHashSet<URL>&) const override;
 
     void didFinishInsertingNode() override;
diff --git a/Source/WebCore/svg/SVGUseElement.cpp b/Source/WebCore/svg/SVGUseElement.cpp
index c69745d..e8ad2e5 100644
--- a/Source/WebCore/svg/SVGUseElement.cpp
+++ b/Source/WebCore/svg/SVGUseElement.cpp
@@ -542,7 +542,7 @@
     return targetClone && targetClone->hasRelativeLengths();
 }
 
-void SVGUseElement::notifyFinished(CachedResource& resource)
+void SVGUseElement::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&)
 {
     ASSERT(ScriptDisallowedScope::InMainThread::isScriptAllowed());
     invalidateShadowTree();
diff --git a/Source/WebCore/svg/SVGUseElement.h b/Source/WebCore/svg/SVGUseElement.h
index 57019c7..69efaff 100644
--- a/Source/WebCore/svg/SVGUseElement.h
+++ b/Source/WebCore/svg/SVGUseElement.h
@@ -70,7 +70,7 @@
     RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) override;
     Path toClipPath() override;
     bool selfHasRelativeLengths() const override;
-    void notifyFinished(CachedResource&) final;
+    void notifyFinished(CachedResource&, const NetworkLoadMetrics&) final;
 
     Document* externalDocument() const;
     void updateExternalDocument();
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index b6d8851..6f9bbf2 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,32 @@
+2020-05-12  Alex Christensen  <achristensen@webkit.org>
+
+        Give some NetworkLoadMetrics to WebCoreNSURLSession's delegate
+        https://bugs.webkit.org/show_bug.cgi?id=211759
+        <rdar://problem/62909440>
+
+        Reviewed by Jer Noble.
+
+        This also reduces duplicate lookups in RemoteMediaResourceManager
+
+        * GPUProcess/media/RemoteMediaResource.cpp:
+        (WebKit::RemoteMediaResource::loadFinished):
+        * GPUProcess/media/RemoteMediaResource.h:
+        * GPUProcess/media/RemoteMediaResourceManager.cpp:
+        (WebKit::RemoteMediaResourceManager::responseReceived):
+        (WebKit::RemoteMediaResourceManager::redirectReceived):
+        (WebKit::RemoteMediaResourceManager::dataSent):
+        (WebKit::RemoteMediaResourceManager::dataReceived):
+        (WebKit::RemoteMediaResourceManager::accessControlCheckFailed):
+        (WebKit::RemoteMediaResourceManager::loadFailed):
+        (WebKit::RemoteMediaResourceManager::loadFinished):
+        * GPUProcess/media/RemoteMediaResourceManager.h:
+        * GPUProcess/media/RemoteMediaResourceManager.messages.in:
+        * NetworkProcess/cocoa/NetworkSessionCocoa.mm:
+        (-[WKNetworkSessionDelegate URLSession:task:didFinishCollectingMetrics:]):
+        * WebProcess/GPU/media/RemoteMediaResourceProxy.cpp:
+        (WebKit::RemoteMediaResourceProxy::loadFinished):
+        * WebProcess/GPU/media/RemoteMediaResourceProxy.h:
+
 2020-05-12  Jiewen Tan  <jiewen_tan@apple.com>
 
         [WebAuthn] Don't assume extensions always exist
diff --git a/Source/WebKit/GPUProcess/media/RemoteMediaResource.cpp b/Source/WebKit/GPUProcess/media/RemoteMediaResource.cpp
index 64150f9..7db36c7 100644
--- a/Source/WebKit/GPUProcess/media/RemoteMediaResource.cpp
+++ b/Source/WebKit/GPUProcess/media/RemoteMediaResource.cpp
@@ -112,10 +112,10 @@
         m_client->loadFailed(*this, error);
 }
 
-void RemoteMediaResource::loadFinished()
+void RemoteMediaResource::loadFinished(const NetworkLoadMetrics& metrics)
 {
     if (m_client)
-        m_client->loadFinished(*this);
+        m_client->loadFinished(*this, metrics);
 }
 
 } // namespace WebKit
diff --git a/Source/WebKit/GPUProcess/media/RemoteMediaResource.h b/Source/WebKit/GPUProcess/media/RemoteMediaResource.h
index 486f6bb..5eaa7cf 100644
--- a/Source/WebKit/GPUProcess/media/RemoteMediaResource.h
+++ b/Source/WebKit/GPUProcess/media/RemoteMediaResource.h
@@ -31,6 +31,10 @@
 #include <WebCore/PlatformMediaResourceLoader.h>
 #include <wtf/WeakPtr.h>
 
+namespace WebCore {
+class NetworkLoadMetrics;
+}
+
 namespace WebKit {
 
 class RemoteMediaPlayerProxy;
@@ -54,7 +58,7 @@
     void dataReceived(const char*, int64_t);
     void accessControlCheckFailed(const WebCore::ResourceError&);
     void loadFailed(const WebCore::ResourceError&);
-    void loadFinished();
+    void loadFinished(const WebCore::NetworkLoadMetrics&);
 
 private:
     RemoteMediaResource(RemoteMediaResourceManager&, RemoteMediaPlayerProxy&, RemoteMediaResourceIdentifier);
diff --git a/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.cpp b/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.cpp
index 134b8ca..08cb496 100644
--- a/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.cpp
+++ b/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.cpp
@@ -67,7 +67,7 @@
         return;
     }
 
-    m_remoteMediaResources.get(id)->responseReceived(response, didPassAccessControlCheck, WTFMove(completionHandler));
+    resource->responseReceived(response, didPassAccessControlCheck, WTFMove(completionHandler));
 }
 
 void RemoteMediaResourceManager::redirectReceived(RemoteMediaResourceIdentifier id, ResourceRequest&& request, const ResourceResponse& response, CompletionHandler<void(WebCore::ResourceRequest&&)>&& completionHandler)
@@ -78,7 +78,7 @@
         return;
     }
 
-    m_remoteMediaResources.get(id)->redirectReceived(WTFMove(request), response, WTFMove(completionHandler));
+    resource->redirectReceived(WTFMove(request), response, WTFMove(completionHandler));
 }
 
 void RemoteMediaResourceManager::dataSent(RemoteMediaResourceIdentifier id, uint64_t bytesSent, uint64_t totalBytesToBeSent)
@@ -87,7 +87,7 @@
     if (!resource || !resource->ready())
         return;
 
-    m_remoteMediaResources.get(id)->dataSent(bytesSent, totalBytesToBeSent);
+    resource->dataSent(bytesSent, totalBytesToBeSent);
 }
 
 void RemoteMediaResourceManager::dataReceived(RemoteMediaResourceIdentifier id, const IPC::DataReference& data)
@@ -96,7 +96,7 @@
     if (!resource || !resource->ready())
         return;
 
-    m_remoteMediaResources.get(id)->dataReceived(reinterpret_cast<const char*>(data.data()), data.size());
+    resource->dataReceived(reinterpret_cast<const char*>(data.data()), data.size());
 }
 
 void RemoteMediaResourceManager::accessControlCheckFailed(RemoteMediaResourceIdentifier id, const ResourceError& error)
@@ -105,7 +105,7 @@
     if (!resource || !resource->ready())
         return;
 
-    m_remoteMediaResources.get(id)->accessControlCheckFailed(error);
+    resource->accessControlCheckFailed(error);
 }
 
 void RemoteMediaResourceManager::loadFailed(RemoteMediaResourceIdentifier id, const ResourceError& error)
@@ -114,16 +114,16 @@
     if (!resource || !resource->ready())
         return;
 
-    m_remoteMediaResources.get(id)->loadFailed(error);
+    resource->loadFailed(error);
 }
 
-void RemoteMediaResourceManager::loadFinished(RemoteMediaResourceIdentifier id)
+void RemoteMediaResourceManager::loadFinished(RemoteMediaResourceIdentifier id, const NetworkLoadMetrics& metrics)
 {
     auto* resource = m_remoteMediaResources.get(id);
     if (!resource || !resource->ready())
         return;
 
-    m_remoteMediaResources.get(id)->loadFinished();
+    resource->loadFinished(metrics);
 }
 
 } // namespace WebKit
diff --git a/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.h b/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.h
index 7750145..d89b803 100644
--- a/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.h
+++ b/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.h
@@ -39,6 +39,7 @@
 }
 
 namespace WebCore {
+class NetworkLoadMetrics;
 class ResourceRequest;
 }
 
@@ -66,7 +67,7 @@
     void dataReceived(RemoteMediaResourceIdentifier, const IPC::DataReference&);
     void accessControlCheckFailed(RemoteMediaResourceIdentifier, const WebCore::ResourceError&);
     void loadFailed(RemoteMediaResourceIdentifier, const WebCore::ResourceError&);
-    void loadFinished(RemoteMediaResourceIdentifier);
+    void loadFinished(RemoteMediaResourceIdentifier, const WebCore::NetworkLoadMetrics&);
 
     HashMap<RemoteMediaResourceIdentifier, RemoteMediaResource*> m_remoteMediaResources;
 };
diff --git a/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.messages.in b/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.messages.in
index 17047c3..09fc4c0 100644
--- a/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.messages.in
+++ b/Source/WebKit/GPUProcess/media/RemoteMediaResourceManager.messages.in
@@ -32,7 +32,7 @@
     DataReceived(WebKit::RemoteMediaResourceIdentifier id, IPC::DataReference data)
     AccessControlCheckFailed(WebKit::RemoteMediaResourceIdentifier id, WebCore::ResourceError error)
     LoadFailed(WebKit::RemoteMediaResourceIdentifier id, WebCore::ResourceError error)
-    LoadFinished(WebKit::RemoteMediaResourceIdentifier id)
+    LoadFinished(WebKit::RemoteMediaResourceIdentifier id, WebCore::NetworkLoadMetrics metrics)
 }
 
 #endif
diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm
index 0ebac05..9066128 100644
--- a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm
+++ b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm
@@ -781,6 +781,7 @@
         NSTimeInterval responseEndInterval = [m.responseEndDate timeIntervalSinceDate:fetchStartDate];
 
         auto& networkLoadMetrics = networkDataTask->networkLoadMetrics();
+        networkLoadMetrics.fetchStart = Seconds(fetchStartDate.timeIntervalSince1970);
         networkLoadMetrics.domainLookupStart = Seconds(domainLookupStartInterval);
         networkLoadMetrics.domainLookupEnd = Seconds(domainLookupEndInterval);
         networkLoadMetrics.connectStart = Seconds(connectStartInterval);
diff --git a/Source/WebKit/WebProcess/GPU/media/RemoteMediaResourceProxy.cpp b/Source/WebKit/WebProcess/GPU/media/RemoteMediaResourceProxy.cpp
index 6a6bbcd..7954a56 100644
--- a/Source/WebKit/WebProcess/GPU/media/RemoteMediaResourceProxy.cpp
+++ b/Source/WebKit/WebProcess/GPU/media/RemoteMediaResourceProxy.cpp
@@ -86,9 +86,9 @@
     m_connection->send(Messages::RemoteMediaResourceManager::LoadFailed(m_id, error), 0);
 }
 
-void RemoteMediaResourceProxy::loadFinished(WebCore::PlatformMediaResource&)
+void RemoteMediaResourceProxy::loadFinished(WebCore::PlatformMediaResource&, const WebCore::NetworkLoadMetrics& metrics)
 {
-    m_connection->send(Messages::RemoteMediaResourceManager::LoadFinished(m_id), 0);
+    m_connection->send(Messages::RemoteMediaResourceManager::LoadFinished(m_id, metrics), 0);
 }
 
 }
diff --git a/Source/WebKit/WebProcess/GPU/media/RemoteMediaResourceProxy.h b/Source/WebKit/WebProcess/GPU/media/RemoteMediaResourceProxy.h
index 953bb30..4d6a5af 100644
--- a/Source/WebKit/WebProcess/GPU/media/RemoteMediaResourceProxy.h
+++ b/Source/WebKit/WebProcess/GPU/media/RemoteMediaResourceProxy.h
@@ -50,7 +50,7 @@
     void dataReceived(WebCore::PlatformMediaResource&, const char*, int) final;
     void accessControlCheckFailed(WebCore::PlatformMediaResource&, const WebCore::ResourceError&) final;
     void loadFailed(WebCore::PlatformMediaResource&, const WebCore::ResourceError&) final;
-    void loadFinished(WebCore::PlatformMediaResource&) final;
+    void loadFinished(WebCore::PlatformMediaResource&, const WebCore::NetworkLoadMetrics&) final;
 
     Ref<IPC::Connection> m_connection;
     WebCore::PlatformMediaResource& m_platformMediaResource;