Title: [213682] trunk
Revision
213682
Author
[email protected]
Date
2017-03-09 15:44:12 -0800 (Thu, 09 Mar 2017)

Log Message

Web Inspector: Show HTTP protocol version and other Network Load Metrics (IP Address, Priority, Connection ID)
https://bugs.webkit.org/show_bug.cgi?id=29687
<rdar://problem/19281586>

Reviewed by Matt Baker and Brian Burg.

Source/_javascript_Core:

* inspector/protocol/Network.json:
Add metrics object with optional properties to loadingFinished event.

Source/WebCore:

Test: http/tests/inspector/network/resource-metrics.html

* inspector/InspectorNetworkAgent.cpp:
(WebCore::toProtocol):
(WebCore::InspectorNetworkAgent::buildObjectForMetrics):
(WebCore::InspectorNetworkAgent::didFinishLoading):
Send metrics at didFinishLoading time, we do not have all of
these at didReceiveResponse time.

* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::didFinishLoadingImpl):
* inspector/InspectorInstrumentation.h:
(WebCore::InspectorInstrumentation::didFinishLoading):
* inspector/InspectorNetworkAgent.h:
* loader/CrossOriginPreflightChecker.cpp:
(WebCore::CrossOriginPreflightChecker::validatePreflightResponse):
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::finishedLoading):
* loader/ResourceLoadNotifier.cpp:
(WebCore::ResourceLoadNotifier::didFinishLoad):
(WebCore::ResourceLoadNotifier::dispatchDidFinishLoading):
(WebCore::ResourceLoadNotifier::sendRemainingDelegateMessages):
* loader/ResourceLoadNotifier.h:
* loader/SubresourceLoader.cpp:
(WebCore::SubresourceLoader::didFinishLoading):
* loader/appcache/ApplicationCacheGroup.cpp:
(WebCore::ApplicationCacheGroup::didFinishLoading):
Include or pass on NetworkLoadMetrics to Web Inspector.

* platform/network/NetworkLoadMetrics.h:
(WebCore::NetworkLoadMetrics::isolatedCopy):
(WebCore::NetworkLoadMetrics::reset):
(WebCore::NetworkLoadMetrics::operator==):
(WebCore::NetworkLoadMetrics::encode):
(WebCore::NetworkLoadMetrics::decode):
Add new optional metrics properties.

(WTF::Persistence::Coder<std::optional<WebCore::NetworkLoadPriority>>::encode):
(WTF::Persistence::Coder<std::optional<WebCore::NetworkLoadPriority>>::decode):
We never encode this but this is needed for the compiler.

* platform/spi/cocoa/NSURLConnectionSPI.h:
New SPI for NSURLSessionTaskTransactionMetrics details.

Source/WebInspectorUI:

These columns are available in the Network DataGrids, but are
initially hidden. They can be shown by right clicking on the
table header and showing these columns. We are going to rework
the default list of visible columns later.

* Localizations/en.lproj/localizedStrings.js:
New localized strings for data grid headers and Low/Medium/High.

* UserInterface/Controllers/FrameResourceManager.js:
(WebInspector.FrameResourceManager.prototype.resourceRequestDidFinishLoading):
* UserInterface/Protocol/NetworkObserver.js:
(WebInspector.NetworkObserver.prototype.loadingFinished):
Pass metrics on to the Resource.

* UserInterface/Models/Resource.js:
(WebInspector.Resource):
(WebInspector.Resource.displayNameForType):
(WebInspector.Resource.responseSourceFromPayload):
(WebInspector.Resource.networkPriorityFromPayload):
(WebInspector.Resource.connectionIdentifierFromPayload):
(WebInspector.Resource.prototype.get protocol):
(WebInspector.Resource.prototype.get priority):
(WebInspector.Resource.prototype.get remoteAddress):
(WebInspector.Resource.prototype.get connectionIdentifier):
(WebInspector.Resource.prototype.updateWithMetrics):
Include metrics accessors and default values.

* UserInterface/Views/NetworkGridContentView.js:
(WebInspector.NetworkGridContentView):
* UserInterface/Views/NetworkTimelineView.js:
(WebInspector.NetworkTimelineView):
Add metrics columns if the backend may be sending them.

* UserInterface/Views/ResourceTimelineDataGridNode.js:
(WebInspector.ResourceTimelineDataGridNode.prototype.get data):
(WebInspector.ResourceTimelineDataGridNode.prototype.createCellContent):
(WebInspector.ResourceTimelineDataGridNode.prototype._displayNameForPriority):
(WebInspector.ResourceTimelineDataGridNode.prototype._cachedCellContent):
Display strings for new columns.

* UserInterface/Views/TimelineDataGridNode.js:
* UserInterface/Views/TimelineRecordBar.js:
(WebInspector.TimelineRecordBar.prototype.refresh):
Avoid assertions if Graph column is unavailable.

* UserInterface/Views/DataGrid.js:
(WebInspector.DataGrid):
(WebInspector.DataGrid.prototype.createSettings):
(WebInspector.DataGrid.prototype.setColumnVisible):
Better support for restoring user preference of initially
hidden columns which the user may have shown.

* UserInterface/Views/ResourceDetailsSidebarPanel.js:
(WebInspector.ResourceDetailsSidebarPanel):
(WebInspector.ResourceDetailsSidebarPanel.prototype._refreshRequestAndResponse):
Show the Protocol and Priority in the Resources sidebar.

Source/WebKit2:

* NetworkProcess/cocoa/NetworkSessionCocoa.mm:
(toNetworkLoadPriority):
(-[WKNetworkSessionDelegate URLSession:task:didFinishCollectingMetrics:]):
* Shared/WebCoreArgumentCoders.h:
Additional optional metrics on NetworkLoadMetrics.

LayoutTests:

* http/tests/inspector/network/resource-metrics-expected.txt: Added.
* http/tests/inspector/network/resource-metrics.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (213681 => 213682)


--- trunk/LayoutTests/ChangeLog	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/LayoutTests/ChangeLog	2017-03-09 23:44:12 UTC (rev 213682)
@@ -1,3 +1,14 @@
+2017-03-09  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Show HTTP protocol version and other Network Load Metrics (IP Address, Priority, Connection ID)
+        https://bugs.webkit.org/show_bug.cgi?id=29687
+        <rdar://problem/19281586>
+
+        Reviewed by Matt Baker and Brian Burg.
+
+        * http/tests/inspector/network/resource-metrics-expected.txt: Added.
+        * http/tests/inspector/network/resource-metrics.html: Added.
+
 2017-03-09  Ryan Haddad  <[email protected]>
 
         Add iOS baseline for compositing/contents-format/subpixel-antialiased-text-traversal.

Added: trunk/LayoutTests/http/tests/inspector/network/resource-metrics-expected.txt (0 => 213682)


--- trunk/LayoutTests/http/tests/inspector/network/resource-metrics-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/inspector/network/resource-metrics-expected.txt	2017-03-09 23:44:12 UTC (rev 213682)
@@ -0,0 +1,13 @@
+Test for Resource metrics (protocol, priority, remoteAddress, connectionIdentifier).
+
+
+== Running test suite: Resource.Metrics
+-- Running test case: Resource.Metrics.Network
+PASS: Resource should be created.
+PASS: Resource should receive a Response.
+PASS: statusCode should be 200.
+PASS: protocol should be null or http/1.1.
+PASS: priority should be Symbol(unknown) or Symbol(medium).
+PASS: remoteAddressType should be null or a string.
+PASS: connectionIdentifierType should be null or string.
+

Added: trunk/LayoutTests/http/tests/inspector/network/resource-metrics.html (0 => 213682)


--- trunk/LayoutTests/http/tests/inspector/network/resource-metrics.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/inspector/network/resource-metrics.html	2017-03-09 23:44:12 UTC (rev 213682)
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src=""
+<script>
+function triggerNetworkLoad() {
+    let url = "" + Math.random();
+    fetch(url).then(() => {
+        TestPage.dispatchEventToFrontend("LoadComplete");
+    });
+}
+
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite("Resource.Metrics");
+
+    function addTestCase({name, description, _expression_, statusCode, protocol, priority, remoteAddressType, connectionIdentifierType}) {
+        suite.addTestCase({
+            name, description,
+            test(resolve, reject) {
+                InspectorTest.evaluateInPage(_expression_);
+                Promise.all([
+                    WebInspector.Frame.awaitEvent(WebInspector.Frame.Event.ResourceWasAdded),
+                    WebInspector.Resource.awaitEvent(WebInspector.Resource.Event.ResponseReceived),
+                    InspectorTest.awaitEvent("LoadComplete"),
+                ]).then(([resourceWasAddedEvent, responseReceivedEvent, loadCompleteEvent]) => {
+                    let resource = resourceWasAddedEvent.data.resource;
+                    InspectorTest.expectThat(resource instanceof WebInspector.Resource, "Resource should be created.");
+                    InspectorTest.expectEqual(resource, responseReceivedEvent.target, "Resource should receive a Response.");
+                    InspectorTest.expectEqual(resource.statusCode, statusCode, `statusCode should be ${statusCode}.`);
+                    InspectorTest.expectThat(resource.protocol === null || resource.protocol === protocol, `protocol should be null or ${protocol}.`);
+                    InspectorTest.expectThat(resource.priority === WebInspector.Resource.NetworkPriority.Unknown || resource.priority === priority, `priority should be ${String(WebInspector.Resource.NetworkPriority.Unknown)} or ${String(priority)}.`);
+                    InspectorTest.expectThat(resource.remoteAddress === null || typeof resource.protocol === remoteAddressType, `remoteAddressType should be null or a ${remoteAddressType}.`);
+                    InspectorTest.expectThat(resource.connectionIdentifier === null || typeof resource.protocol === connectionIdentifierType, `connectionIdentifierType should be null or ${connectionIdentifierType}.`);
+                }).then(resolve, reject);
+            }
+        });
+    }
+
+    addTestCase({
+        name: "Resource.Metrics.Network",
+        description: "Load a resource from the network by giving a random URL should have metrics.",
+        _expression_: `triggerNetworkLoad()`,
+        statusCode: 200,
+        protocol: "http/1.1",
+        priority: WebInspector.Resource.NetworkPriority.Medium,
+        remoteAddressType: "string",
+        connectionIdentifierType: "string",
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<p>Test for Resource metrics (protocol, priority, remoteAddress, connectionIdentifier).</p>
+</body>
+</html>

Modified: trunk/Source/_javascript_Core/ChangeLog (213681 => 213682)


--- trunk/Source/_javascript_Core/ChangeLog	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-03-09 23:44:12 UTC (rev 213682)
@@ -1,3 +1,14 @@
+2017-03-09  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Show HTTP protocol version and other Network Load Metrics (IP Address, Priority, Connection ID)
+        https://bugs.webkit.org/show_bug.cgi?id=29687
+        <rdar://problem/19281586>
+
+        Reviewed by Matt Baker and Brian Burg.
+
+        * inspector/protocol/Network.json:
+        Add metrics object with optional properties to loadingFinished event.
+
 2017-03-09  Youenn Fablet  <[email protected]>
 
         Minimal build is broken

Modified: trunk/Source/_javascript_Core/inspector/protocol/Network.json (213681 => 213682)


--- trunk/Source/_javascript_Core/inspector/protocol/Network.json	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/_javascript_Core/inspector/protocol/Network.json	2017-03-09 23:44:12 UTC (rev 213682)
@@ -77,6 +77,17 @@
             ]
         },
         {
+            "id": "Metrics",
+            "type": "object",
+            "description": "Network load metrics.",
+            "properties": [
+                { "name": "protocol", "type": "string", "optional": true, "description": "Network protocol. ALPN Protocol ID Identification Sequence, as per RFC 7301 (for example, http/2, http/1.1, spdy/3.1)" },
+                { "name": "priority", "type": "string", "enum": ["low", "medium", "high"], "optional": true, "description": "Network priority." },
+                { "name": "connectionIdentifier", "type": "string", "optional": true, "description": "Connection identifier." },
+                { "name": "remoteAddress", "type": "string", "optional": true, "description": "Remote IP address." }
+            ]
+        },
+        {
             "id": "WebSocketRequest",
             "type": "object",
             "description": "WebSocket request data.",
@@ -229,7 +240,8 @@
             "parameters": [
                 { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." },
                 { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." },
-                { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with this resource (if any)." }
+                { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with this resource (if any)." },
+                { "name": "metrics", "$ref": "Metrics", "optional": true, "description": "Network metrics." }
             ]
         },
         {

Modified: trunk/Source/WebCore/ChangeLog (213681 => 213682)


--- trunk/Source/WebCore/ChangeLog	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/ChangeLog	2017-03-09 23:44:12 UTC (rev 213682)
@@ -1,3 +1,55 @@
+2017-03-09  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Show HTTP protocol version and other Network Load Metrics (IP Address, Priority, Connection ID)
+        https://bugs.webkit.org/show_bug.cgi?id=29687
+        <rdar://problem/19281586>
+
+        Reviewed by Matt Baker and Brian Burg.
+
+        Test: http/tests/inspector/network/resource-metrics.html
+
+        * inspector/InspectorNetworkAgent.cpp:
+        (WebCore::toProtocol):
+        (WebCore::InspectorNetworkAgent::buildObjectForMetrics):
+        (WebCore::InspectorNetworkAgent::didFinishLoading):
+        Send metrics at didFinishLoading time, we do not have all of
+        these at didReceiveResponse time.
+
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::didFinishLoadingImpl):
+        * inspector/InspectorInstrumentation.h:
+        (WebCore::InspectorInstrumentation::didFinishLoading):
+        * inspector/InspectorNetworkAgent.h:
+        * loader/CrossOriginPreflightChecker.cpp:
+        (WebCore::CrossOriginPreflightChecker::validatePreflightResponse):
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::finishedLoading):
+        * loader/ResourceLoadNotifier.cpp:
+        (WebCore::ResourceLoadNotifier::didFinishLoad):
+        (WebCore::ResourceLoadNotifier::dispatchDidFinishLoading):
+        (WebCore::ResourceLoadNotifier::sendRemainingDelegateMessages):
+        * loader/ResourceLoadNotifier.h:
+        * loader/SubresourceLoader.cpp:
+        (WebCore::SubresourceLoader::didFinishLoading):
+        * loader/appcache/ApplicationCacheGroup.cpp:
+        (WebCore::ApplicationCacheGroup::didFinishLoading):
+        Include or pass on NetworkLoadMetrics to Web Inspector.
+
+        * platform/network/NetworkLoadMetrics.h:
+        (WebCore::NetworkLoadMetrics::isolatedCopy):
+        (WebCore::NetworkLoadMetrics::reset):
+        (WebCore::NetworkLoadMetrics::operator==):
+        (WebCore::NetworkLoadMetrics::encode):
+        (WebCore::NetworkLoadMetrics::decode):
+        Add new optional metrics properties.
+
+        (WTF::Persistence::Coder<std::optional<WebCore::NetworkLoadPriority>>::encode):
+        (WTF::Persistence::Coder<std::optional<WebCore::NetworkLoadPriority>>::decode):
+        We never encode this but this is needed for the compiler.
+
+        * platform/spi/cocoa/NSURLConnectionSPI.h:
+        New SPI for NSURLSessionTaskTransactionMetrics details.
+
 2017-03-09  Anders Carlsson  <[email protected]>
 
         Use the right conditional.

Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp (213681 => 213682)


--- trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp	2017-03-09 23:44:12 UTC (rev 213682)
@@ -599,13 +599,13 @@
         networkAgent->didReceiveData(identifier, data, dataLength, encodedDataLength);
 }
 
-void InspectorInstrumentation::didFinishLoadingImpl(InstrumentingAgents& instrumentingAgents, unsigned long identifier, DocumentLoader* loader)
+void InspectorInstrumentation::didFinishLoadingImpl(InstrumentingAgents& instrumentingAgents, unsigned long identifier, DocumentLoader* loader, const NetworkLoadMetrics& networkLoadMetrics)
 {
     if (!loader)
         return;
 
     if (InspectorNetworkAgent* networkAgent = instrumentingAgents.inspectorNetworkAgent())
-        networkAgent->didFinishLoading(identifier, *loader);
+        networkAgent->didFinishLoading(identifier, *loader, networkLoadMetrics);
 }
 
 void InspectorInstrumentation::didFailLoadingImpl(InstrumentingAgents& instrumentingAgents, unsigned long identifier, DocumentLoader* loader, const ResourceError& error)

Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.h (213681 => 213682)


--- trunk/Source/WebCore/inspector/InspectorInstrumentation.h	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.h	2017-03-09 23:44:12 UTC (rev 213682)
@@ -71,6 +71,7 @@
 class HTTPHeaderMap;
 class InspectorTimelineAgent;
 class InstrumentingAgents;
+class NetworkLoadMetrics;
 class Node;
 class PseudoElement;
 class RenderLayer;
@@ -156,7 +157,7 @@
     static void didReceiveResourceResponse(Frame&, unsigned long identifier, DocumentLoader*, const ResourceResponse&, ResourceLoader*);
     static void didReceiveThreadableLoaderResponse(DocumentThreadableLoader&, unsigned long identifier);
     static void didReceiveData(Frame*, unsigned long identifier, const char* data, int dataLength, int encodedDataLength);
-    static void didFinishLoading(Frame*, DocumentLoader*, unsigned long identifier);
+    static void didFinishLoading(Frame*, DocumentLoader*, unsigned long identifier, const NetworkLoadMetrics&);
     static void didFailLoading(Frame*, DocumentLoader*, unsigned long identifier, const ResourceError&);
     static void continueAfterXFrameOptionsDenied(Frame&, unsigned long identifier, DocumentLoader&, const ResourceResponse&);
     static void continueWithPolicyDownload(Frame&, unsigned long identifier, DocumentLoader&, const ResourceResponse&);
@@ -326,7 +327,7 @@
     static void didReceiveResourceResponseImpl(InstrumentingAgents&, unsigned long identifier, DocumentLoader*, const ResourceResponse&, ResourceLoader*);
     static void didReceiveThreadableLoaderResponseImpl(InstrumentingAgents&, DocumentThreadableLoader&, unsigned long identifier);
     static void didReceiveDataImpl(InstrumentingAgents&, unsigned long identifier, const char* data, int dataLength, int encodedDataLength);
-    static void didFinishLoadingImpl(InstrumentingAgents&, unsigned long identifier, DocumentLoader*);
+    static void didFinishLoadingImpl(InstrumentingAgents&, unsigned long identifier, DocumentLoader*, const NetworkLoadMetrics&);
     static void didFailLoadingImpl(InstrumentingAgents&, unsigned long identifier, DocumentLoader*, const ResourceError&);
     static void didFinishXHRLoadingImpl(InstrumentingAgents&, unsigned long identifier, std::optional<String> decodedText, const String& url, const String& sendURL, unsigned sendLineNumber, unsigned sendColumnNumber);
     static void willLoadXHRSynchronouslyImpl(InstrumentingAgents&);
@@ -857,10 +858,10 @@
         didReceiveDataImpl(*instrumentingAgents, identifier, data, dataLength, encodedDataLength);
 }
 
-inline void InspectorInstrumentation::didFinishLoading(Frame* frame, DocumentLoader* loader, unsigned long identifier)
+inline void InspectorInstrumentation::didFinishLoading(Frame* frame, DocumentLoader* loader, unsigned long identifier, const NetworkLoadMetrics& networkLoadMetrics)
 {
     if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
-        didFinishLoadingImpl(*instrumentingAgents, identifier, loader);
+        didFinishLoadingImpl(*instrumentingAgents, identifier, loader, networkLoadMetrics);
 }
 
 inline void InspectorInstrumentation::didFailLoading(Frame* frame, DocumentLoader* loader, unsigned long identifier, const ResourceError& error)

Modified: trunk/Source/WebCore/inspector/InspectorNetworkAgent.cpp (213681 => 213682)


--- trunk/Source/WebCore/inspector/InspectorNetworkAgent.cpp	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/inspector/InspectorNetworkAgent.cpp	2017-03-09 23:44:12 UTC (rev 213682)
@@ -196,6 +196,37 @@
         .release();
 }
 
+static Inspector::Protocol::Network::Metrics::Priority toProtocol(NetworkLoadPriority priority)
+{
+    switch (priority) {
+    case NetworkLoadPriority::Low:
+        return Inspector::Protocol::Network::Metrics::Priority::Low;
+    case NetworkLoadPriority::Medium:
+        return Inspector::Protocol::Network::Metrics::Priority::Medium;
+    case NetworkLoadPriority::High:
+        return Inspector::Protocol::Network::Metrics::Priority::High;
+    }
+
+    ASSERT_NOT_REACHED();
+    return Inspector::Protocol::Network::Metrics::Priority::Medium;
+}
+
+Ref<Inspector::Protocol::Network::Metrics> InspectorNetworkAgent::buildObjectForMetrics(const NetworkLoadMetrics& networkLoadMetrics)
+{
+    auto metrics = Inspector::Protocol::Network::Metrics::create().release();
+
+    if (!networkLoadMetrics.protocol.isNull())
+        metrics->setProtocol(networkLoadMetrics.protocol);
+    if (networkLoadMetrics.priority)
+        metrics->setPriority(toProtocol(*networkLoadMetrics.priority));
+    if (networkLoadMetrics.remoteAddress)
+        metrics->setRemoteAddress(*networkLoadMetrics.remoteAddress);
+    if (networkLoadMetrics.connectionIdentifier)
+        metrics->setConnectionIdentifier(*networkLoadMetrics.connectionIdentifier);
+
+    return metrics;
+}
+
 static Ref<Inspector::Protocol::Network::Request> buildObjectForResourceRequest(const ResourceRequest& request)
 {
     auto requestObject = Inspector::Protocol::Network::Request::create()
@@ -391,12 +422,12 @@
     m_frontendDispatcher->dataReceived(requestId, timestamp(), dataLength, encodedDataLength);
 }
 
-void InspectorNetworkAgent::didFinishLoading(unsigned long identifier, DocumentLoader& loader)
+void InspectorNetworkAgent::didFinishLoading(unsigned long identifier, DocumentLoader& loader, const NetworkLoadMetrics& networkLoadMetrics)
 {
     if (m_hiddenRequestIdentifiers.remove(identifier))
         return;
 
-    // FIXME: Inspector should make use of NetworkLoadMetrics.
+    // FIXME: We should use the NetworkLoadMetrics's responseEnd to match ResourceTiming.
     double elapsedFinishTime = timestamp();
 
     String requestId = IdentifiersFactory::requestId(identifier);
@@ -410,7 +441,9 @@
     if (resourceData && resourceData->cachedResource())
         sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(resourceData->cachedResource());
 
-    m_frontendDispatcher->loadingFinished(requestId, elapsedFinishTime, !sourceMappingURL.isEmpty() ? &sourceMappingURL : nullptr);
+    RefPtr<Inspector::Protocol::Network::Metrics> metrics = buildObjectForMetrics(networkLoadMetrics);
+
+    m_frontendDispatcher->loadingFinished(requestId, elapsedFinishTime, !sourceMappingURL.isEmpty() ? &sourceMappingURL : nullptr, metrics);
 }
 
 void InspectorNetworkAgent::didFailLoading(unsigned long identifier, DocumentLoader& loader, const ResourceError& error)

Modified: trunk/Source/WebCore/inspector/InspectorNetworkAgent.h (213681 => 213682)


--- trunk/Source/WebCore/inspector/InspectorNetworkAgent.h	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/inspector/InspectorNetworkAgent.h	2017-03-09 23:44:12 UTC (rev 213682)
@@ -78,7 +78,7 @@
     void willSendRequest(unsigned long identifier, DocumentLoader&, ResourceRequest&, const ResourceResponse& redirectResponse);
     void didReceiveResponse(unsigned long identifier, DocumentLoader&, const ResourceResponse&, ResourceLoader*);
     void didReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength);
-    void didFinishLoading(unsigned long identifier, DocumentLoader&);
+    void didFinishLoading(unsigned long identifier, DocumentLoader&, const NetworkLoadMetrics&);
     void didFailLoading(unsigned long identifier, DocumentLoader&, const ResourceError&);
     void didLoadResourceFromMemoryCache(DocumentLoader&, CachedResource&);
     void didReceiveThreadableLoaderResponse(unsigned long identifier, DocumentThreadableLoader&);
@@ -117,6 +117,7 @@
     void enable();
 
     Ref<Inspector::Protocol::Network::ResourceTiming> buildObjectForTiming(const NetworkLoadMetrics&, ResourceLoader&);
+    Ref<Inspector::Protocol::Network::Metrics> buildObjectForMetrics(const NetworkLoadMetrics&);
     RefPtr<Inspector::Protocol::Network::Response> buildObjectForResourceResponse(const ResourceResponse&, ResourceLoader*);
     Ref<Inspector::Protocol::Network::CachedResource> buildObjectForCachedResource(CachedResource*);
 

Modified: trunk/Source/WebCore/loader/CrossOriginPreflightChecker.cpp (213681 => 213682)


--- trunk/Source/WebCore/loader/CrossOriginPreflightChecker.cpp	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/loader/CrossOriginPreflightChecker.cpp	2017-03-09 23:44:12 UTC (rev 213682)
@@ -39,6 +39,7 @@
 #include "CrossOriginPreflightResultCache.h"
 #include "DocumentThreadableLoader.h"
 #include "InspectorInstrumentation.h"
+#include "NetworkLoadMetrics.h"
 #include "RuntimeEnabledFeatures.h"
 
 namespace WebCore {
@@ -82,8 +83,9 @@
     // FIXME: <https://webkit.org/b/164889> Web Inspector: Show Preflight Request information in inspector
     // This is only showing success preflight requests and responses but we should show network events
     // for preflight failures and distinguish them better from non-preflight requests.
+    NetworkLoadMetrics emptyMetrics;
     InspectorInstrumentation::didReceiveResourceResponse(*frame, identifier, frame->loader().documentLoader(), response, nullptr);
-    InspectorInstrumentation::didFinishLoading(frame, frame->loader().documentLoader(), identifier);
+    InspectorInstrumentation::didFinishLoading(frame, frame->loader().documentLoader(), identifier, emptyMetrics);
 
     CrossOriginPreflightResultCache::singleton().appendEntry(loader.securityOrigin().toString(), request.url(), WTFMove(result));
     loader.preflightSuccess(WTFMove(request));

Modified: trunk/Source/WebCore/loader/DocumentLoader.cpp (213681 => 213682)


--- trunk/Source/WebCore/loader/DocumentLoader.cpp	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/loader/DocumentLoader.cpp	2017-03-09 23:44:12 UTC (rev 213682)
@@ -62,6 +62,7 @@
 #include "Logging.h"
 #include "MainFrame.h"
 #include "MemoryCache.h"
+#include "NetworkLoadMetrics.h"
 #include "Page.h"
 #include "PolicyChecker.h"
 #include "ProgressTracker.h"
@@ -390,9 +391,10 @@
         // being finished). Clear m_identifierForLoadWithoutResourceLoader
         // before calling dispatchDidFinishLoading so that we don't later try to
         // cancel the already-finished substitute load.
+        NetworkLoadMetrics emptyMetrics;
         unsigned long identifier = m_identifierForLoadWithoutResourceLoader;
         m_identifierForLoadWithoutResourceLoader = 0;
-        frameLoader()->notifier().dispatchDidFinishLoading(this, identifier);
+        frameLoader()->notifier().dispatchDidFinishLoading(this, identifier, emptyMetrics);
     }
 
     maybeFinishLoadingMultipartContent();

Modified: trunk/Source/WebCore/loader/ResourceLoadNotifier.cpp (213681 => 213682)


--- trunk/Source/WebCore/loader/ResourceLoadNotifier.cpp	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/loader/ResourceLoadNotifier.cpp	2017-03-09 23:44:12 UTC (rev 213682)
@@ -87,14 +87,12 @@
     dispatchDidReceiveData(loader->documentLoader(), loader->identifier(), data, dataLength, encodedDataLength);
 }
 
-void ResourceLoadNotifier::didFinishLoad(ResourceLoader* loader, const NetworkLoadMetrics&)
+void ResourceLoadNotifier::didFinishLoad(ResourceLoader* loader, const NetworkLoadMetrics& networkLoadMetrics)
 {    
     if (Page* page = m_frame.page())
         page->progress().completeProgress(loader->identifier());
 
-    // FIXME: Inspector should make use of NetworkLoadMetrics.
-
-    dispatchDidFinishLoading(loader->documentLoader(), loader->identifier());
+    dispatchDidFinishLoading(loader->documentLoader(), loader->identifier(), networkLoadMetrics);
 }
 
 void ResourceLoadNotifier::didFailToLoad(ResourceLoader* loader, const ResourceError& error)
@@ -162,13 +160,13 @@
     InspectorInstrumentation::didReceiveData(&m_frame, identifier, data, dataLength, encodedDataLength);
 }
 
-void ResourceLoadNotifier::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier)
+void ResourceLoadNotifier::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier, const NetworkLoadMetrics& networkLoadMetrics)
 {
     // Notifying the FrameLoaderClient may cause the frame to be destroyed.
     Ref<Frame> protect(m_frame);
     m_frame.loader().client().dispatchDidFinishLoading(loader, identifier);
 
-    InspectorInstrumentation::didFinishLoading(&m_frame, loader, identifier);
+    InspectorInstrumentation::didFinishLoading(&m_frame, loader, identifier, networkLoadMetrics);
 }
 
 void ResourceLoadNotifier::dispatchDidFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& error)
@@ -196,9 +194,10 @@
     if (dataLength > 0)
         dispatchDidReceiveData(loader, identifier, data, dataLength, encodedDataLength);
 
-    if (error.isNull())
-        dispatchDidFinishLoading(loader, identifier);
-    else
+    if (error.isNull()) {
+        NetworkLoadMetrics emptyMetrics;
+        dispatchDidFinishLoading(loader, identifier, emptyMetrics);
+    } else
         dispatchDidFailLoading(loader, identifier, error);
 }
 

Modified: trunk/Source/WebCore/loader/ResourceLoadNotifier.h (213681 => 213682)


--- trunk/Source/WebCore/loader/ResourceLoadNotifier.h	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/loader/ResourceLoadNotifier.h	2017-03-09 23:44:12 UTC (rev 213682)
@@ -60,7 +60,7 @@
     void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse);
     void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&, ResourceLoader* = nullptr);
     void dispatchDidReceiveData(DocumentLoader*, unsigned long identifier, const char* data, int dataLength, int encodedDataLength);
-    void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier);
+    void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier, const NetworkLoadMetrics&);
     void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&);
 
     void sendRemainingDelegateMessages(DocumentLoader*, unsigned long identifier, const ResourceRequest&, const ResourceResponse&, const char* data, int dataLength, int encodedDataLength, const ResourceError&);

Modified: trunk/Source/WebCore/loader/SubresourceLoader.cpp (213681 => 213682)


--- trunk/Source/WebCore/loader/SubresourceLoader.cpp	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/loader/SubresourceLoader.cpp	2017-03-09 23:44:12 UTC (rev 213682)
@@ -559,7 +559,7 @@
         return;
     m_resource->finish();
     ASSERT(!reachedTerminalState());
-    didFinishLoadingOnePart(m_resource->response().deprecatedNetworkLoadMetrics());
+    didFinishLoadingOnePart(networkLoadMetrics);
     notifyDone();
     if (reachedTerminalState())
         return;

Modified: trunk/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp (213681 => 213682)


--- trunk/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp	2017-03-09 23:44:12 UTC (rev 213682)
@@ -41,6 +41,7 @@
 #include "HTTPHeaderNames.h"
 #include "InspectorInstrumentation.h"
 #include "ManifestParser.h"
+#include "NetworkLoadMetrics.h"
 #include "Page.h"
 #include "ProgressTracker.h"
 #include "ResourceHandle.h"
@@ -572,7 +573,9 @@
 
 void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle)
 {
-    InspectorInstrumentation::didFinishLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier);
+    // FIXME: We should have NetworkLoadMetrics for ApplicationCache loads.
+    NetworkLoadMetrics emptyMetrics;
+    InspectorInstrumentation::didFinishLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, emptyMetrics);
 
     if (handle == m_manifestHandle) {
         didFinishLoadingManifest();

Modified: trunk/Source/WebCore/platform/network/NetworkLoadMetrics.h (213681 => 213682)


--- trunk/Source/WebCore/platform/network/NetworkLoadMetrics.h	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/platform/network/NetworkLoadMetrics.h	2017-03-09 23:44:12 UTC (rev 213682)
@@ -26,7 +26,10 @@
 
 #pragma once
 
+#include <wtf/Optional.h>
 #include <wtf/Seconds.h>
+#include <wtf/persistence/Decoder.h>
+#include <wtf/persistence/Encoder.h>
 #include <wtf/text/WTFString.h>
 
 #if PLATFORM(COCOA)
@@ -35,6 +38,12 @@
 
 namespace WebCore {
 
+enum class NetworkLoadPriority {
+    Low,
+    Medium,
+    High,
+};
+
 class NetworkLoadMetrics {
 public:
     NetworkLoadMetrics()
@@ -57,6 +66,13 @@
         copy.complete = complete;
         copy.protocol = protocol.isolatedCopy();
 
+        if (remoteAddress)
+            copy.remoteAddress = remoteAddress.value().isolatedCopy();
+        if (connectionIdentifier)
+            copy.connectionIdentifier = connectionIdentifier.value().isolatedCopy();
+        if (priority)
+            copy.priority = *priority;
+
         return copy;
     }
 
@@ -70,8 +86,11 @@
         requestStart = Seconds(0);
         responseStart = Seconds(0);
         responseEnd = Seconds(0);
+        complete = false;
         protocol = String();
-        complete = false;
+        remoteAddress = std::nullopt;
+        connectionIdentifier = std::nullopt;
+        priority = std::nullopt;
     }
 
     bool operator==(const NetworkLoadMetrics& other) const
@@ -85,7 +104,10 @@
             && responseStart == other.responseStart
             && responseEnd == other.responseEnd
             && complete == other.complete
-            && protocol == other.protocol;
+            && protocol == other.protocol
+            && remoteAddress == other.remoteAddress
+            && connectionIdentifier == other.connectionIdentifier
+            && priority == other.priority;
     }
 
     bool operator!=(const NetworkLoadMetrics& other) const
@@ -115,6 +137,10 @@
 
     // ALPN Protocol ID: https://w3c.github.io/resource-timing/#bib-RFC7301
     String protocol;
+
+    std::optional<String> remoteAddress;
+    std::optional<String> connectionIdentifier;
+    std::optional<NetworkLoadPriority> priority;
 };
 
 #if PLATFORM(COCOA)
@@ -138,21 +164,46 @@
     encoder << responseEnd;
     encoder << complete;
     encoder << protocol;
+    encoder << remoteAddress;
+    encoder << connectionIdentifier;
+    encoder << priority;
 }
 
 template<class Decoder>
-bool NetworkLoadMetrics::decode(Decoder& decoder, NetworkLoadMetrics& timing)
+bool NetworkLoadMetrics::decode(Decoder& decoder, NetworkLoadMetrics& metrics)
 {
-    return decoder.decode(timing.domainLookupStart)
-        && decoder.decode(timing.domainLookupEnd)
-        && decoder.decode(timing.connectStart)
-        && decoder.decode(timing.secureConnectionStart)
-        && decoder.decode(timing.connectEnd)
-        && decoder.decode(timing.requestStart)
-        && decoder.decode(timing.responseStart)
-        && decoder.decode(timing.responseEnd)
-        && decoder.decode(timing.complete)
-        && decoder.decode(timing.protocol);
+    return decoder.decode(metrics.domainLookupStart)
+        && decoder.decode(metrics.domainLookupEnd)
+        && decoder.decode(metrics.connectStart)
+        && decoder.decode(metrics.secureConnectionStart)
+        && decoder.decode(metrics.connectEnd)
+        && decoder.decode(metrics.requestStart)
+        && decoder.decode(metrics.responseStart)
+        && decoder.decode(metrics.responseEnd)
+        && decoder.decode(metrics.complete)
+        && decoder.decode(metrics.protocol)
+        && decoder.decode(metrics.remoteAddress)
+        && decoder.decode(metrics.connectionIdentifier)
+        && decoder.decode(metrics.priority);
 }
 
-}
+} // namespace WebCore
+
+// NetworkLoadMetrics should not be stored by the WTF::Persistence::Decoder.
+namespace WTF {
+namespace Persistence {
+
+template<> struct Coder<std::optional<WebCore::NetworkLoadPriority>> {
+    static NO_RETURN_DUE_TO_ASSERT void encode(Encoder&, const std::optional<WebCore::NetworkLoadPriority>&)
+    {
+        ASSERT_NOT_REACHED();
+    }
+
+    static bool decode(Decoder&, std::optional<WebCore::NetworkLoadPriority>&)
+    {
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+};
+
+}} // namespace WTF::Persistence

Modified: trunk/Source/WebCore/platform/spi/cocoa/NSURLConnectionSPI.h (213681 => 213682)


--- trunk/Source/WebCore/platform/spi/cocoa/NSURLConnectionSPI.h	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebCore/platform/spi/cocoa/NSURLConnectionSPI.h	2017-03-09 23:44:12 UTC (rev 213682)
@@ -46,4 +46,11 @@
 - (NSDictionary *)_timingData;
 @end
 
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000)
+@interface NSURLSessionTaskTransactionMetrics ()
+@property (copy, readonly) NSString* _remoteAddressAndPort;
+@property (copy, readonly) NSUUID* _connectionIdentifier;
+@end
 #endif
+
+#endif

Modified: trunk/Source/WebInspectorUI/ChangeLog (213681 => 213682)


--- trunk/Source/WebInspectorUI/ChangeLog	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/ChangeLog	2017-03-09 23:44:12 UTC (rev 213682)
@@ -1,3 +1,68 @@
+2017-03-09  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Show HTTP protocol version and other Network Load Metrics (IP Address, Priority, Connection ID)
+        https://bugs.webkit.org/show_bug.cgi?id=29687
+        <rdar://problem/19281586>
+
+        Reviewed by Matt Baker and Brian Burg.
+
+        These columns are available in the Network DataGrids, but are
+        initially hidden. They can be shown by right clicking on the
+        table header and showing these columns. We are going to rework
+        the default list of visible columns later.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        New localized strings for data grid headers and Low/Medium/High.
+
+        * UserInterface/Controllers/FrameResourceManager.js:
+        (WebInspector.FrameResourceManager.prototype.resourceRequestDidFinishLoading):
+        * UserInterface/Protocol/NetworkObserver.js:
+        (WebInspector.NetworkObserver.prototype.loadingFinished):
+        Pass metrics on to the Resource.
+
+        * UserInterface/Models/Resource.js:
+        (WebInspector.Resource):
+        (WebInspector.Resource.displayNameForType):
+        (WebInspector.Resource.responseSourceFromPayload):
+        (WebInspector.Resource.networkPriorityFromPayload):
+        (WebInspector.Resource.connectionIdentifierFromPayload):
+        (WebInspector.Resource.prototype.get protocol):
+        (WebInspector.Resource.prototype.get priority):
+        (WebInspector.Resource.prototype.get remoteAddress):
+        (WebInspector.Resource.prototype.get connectionIdentifier):
+        (WebInspector.Resource.prototype.updateWithMetrics):
+        Include metrics accessors and default values.
+
+        * UserInterface/Views/NetworkGridContentView.js:
+        (WebInspector.NetworkGridContentView):
+        * UserInterface/Views/NetworkTimelineView.js:
+        (WebInspector.NetworkTimelineView):
+        Add metrics columns if the backend may be sending them.
+
+        * UserInterface/Views/ResourceTimelineDataGridNode.js:
+        (WebInspector.ResourceTimelineDataGridNode.prototype.get data):
+        (WebInspector.ResourceTimelineDataGridNode.prototype.createCellContent):
+        (WebInspector.ResourceTimelineDataGridNode.prototype._displayNameForPriority):
+        (WebInspector.ResourceTimelineDataGridNode.prototype._cachedCellContent):
+        Display strings for new columns.
+
+        * UserInterface/Views/TimelineDataGridNode.js:
+        * UserInterface/Views/TimelineRecordBar.js:
+        (WebInspector.TimelineRecordBar.prototype.refresh):
+        Avoid assertions if Graph column is unavailable.
+
+        * UserInterface/Views/DataGrid.js:
+        (WebInspector.DataGrid):
+        (WebInspector.DataGrid.prototype.createSettings):
+        (WebInspector.DataGrid.prototype.setColumnVisible):
+        Better support for restoring user preference of initially
+        hidden columns which the user may have shown.
+
+        * UserInterface/Views/ResourceDetailsSidebarPanel.js:
+        (WebInspector.ResourceDetailsSidebarPanel):
+        (WebInspector.ResourceDetailsSidebarPanel.prototype._refreshRequestAndResponse):
+        Show the Protocol and Priority in the Resources sidebar.
+
 2017-03-09  Nikita Vasilyev  <[email protected]>
 
         Web Inspector: Show individual messages in the content pane for a WebSocket

Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -416,6 +416,7 @@
 localizedStrings["Hide the navigation sidebar (%s)"] = "Hide the navigation sidebar (%s)";
 localizedStrings["Hide type information"] = "Hide type information";
 localizedStrings["Hierarchy Level"] = "Hierarchy Level";
+localizedStrings["High"] = "High";
 localizedStrings["Highest: %s"] = "Highest: %s";
 localizedStrings["Horizontal"] = "Horizontal";
 localizedStrings["Host"] = "Host";
@@ -492,6 +493,7 @@
 localizedStrings["Log Value"] = "Log Value";
 localizedStrings["Log: "] = "Log: ";
 localizedStrings["Logs"] = "Logs";
+localizedStrings["Low"] = "Low";
 localizedStrings["Lowest: %s"] = "Lowest: %s";
 localizedStrings["MIME Type"] = "MIME Type";
 localizedStrings["Main"] = "Main";
@@ -505,6 +507,7 @@
 localizedStrings["Maximum Size: %s"] = "Maximum Size: %s";
 localizedStrings["Maximum maximum memory size in this recording"] = "Maximum maximum memory size in this recording";
 localizedStrings["Media: "] = "Media: ";
+localizedStrings["Medium"] = "Medium";
 localizedStrings["Memory"] = "Memory";
 localizedStrings["Memory: %s"] = "Memory: %s";
 localizedStrings["Message"] = "Message";
@@ -605,6 +608,7 @@
 localizedStrings["Pretty print"] = "Pretty print";
 localizedStrings["Primary Key"] = "Primary Key";
 localizedStrings["Primary Key \u2014 %s"] = "Primary Key \u2014 %s";
+localizedStrings["Priority"] = "Priority";
 localizedStrings["Probe _expression_"] = "Probe _expression_";
 localizedStrings["Probe Sample Recorded"] = "Probe Sample Recorded";
 localizedStrings["Probes"] = "Probes";
@@ -611,6 +615,7 @@
 localizedStrings["Processing Instruction"] = "Processing Instruction";
 localizedStrings["Properties"] = "Properties";
 localizedStrings["Property"] = "Property";
+localizedStrings["Protocol"] = "Protocol";
 localizedStrings["Query Parameters"] = "Query Parameters";
 localizedStrings["Query String"] = "Query String";
 localizedStrings["Query returned no results."] = "Query returned no results.";
@@ -630,6 +635,7 @@
 localizedStrings["Region Flow"] = "Region Flow";
 localizedStrings["Region announced in its entirety."] = "Region announced in its entirety.";
 localizedStrings["Reload page (%s)\nReload ignoring cache (%s)"] = "Reload page (%s)\nReload ignoring cache (%s)";
+localizedStrings["Remote Address"] = "Remote Address";
 localizedStrings["Removals"] = "Removals";
 localizedStrings["Remove Watch _expression_"] = "Remove Watch _expression_";
 localizedStrings["Remove link"] = "Remove link";

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -414,7 +414,7 @@
             resource.increaseTransferSize(encodedDataLength);
     }
 
-    resourceRequestDidFinishLoading(requestIdentifier, timestamp, sourceMapURL)
+    resourceRequestDidFinishLoading(requestIdentifier, timestamp, sourceMapURL, metrics)
     {
         // Called from WebInspector.NetworkObserver.
 
@@ -429,7 +429,10 @@
         if (!resource)
             return;
 
-        var elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
+        if (metrics)
+            resource.updateWithMetrics(metrics);
+
+        let elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
         resource.markAsFinished(elapsedTime);
 
         if (sourceMapURL)
@@ -453,7 +456,7 @@
         if (!resource)
             return;
 
-        var elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
+        let elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
         resource.markAsFailed(canceled, elapsedTime);
 
         if (resource === resource.parentFrame.provisionalMainResource)

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -63,6 +63,10 @@
         this._cached = false;
         this._responseSource = WebInspector.Resource.ResponseSource.Unknown;
         this._timingData = new WebInspector.ResourceTimingData(this);
+        this._protocol = null;
+        this._priority = WebInspector.Resource.NetworkPriority.Unknown;
+        this._remoteAddress = null;
+        this._connectionIdentifier = null;
         this._target = targetId ? WebInspector.targetManager.targetForIdentifier(targetId) : WebInspector.mainTarget;
 
         if (this._initiatorSourceCodeLocation && this._initiatorSourceCodeLocation.sourceCode instanceof WebInspector.Resource)
@@ -128,7 +132,7 @@
         case WebInspector.Resource.Type.Other:
             return WebInspector.UIString("Other");
         default:
-            console.error("Unknown resource type: ", type);
+            console.error("Unknown resource type", type);
             return null;
         }
     }
@@ -148,11 +152,43 @@
         case NetworkAgent.ResponseSource.DiskCache:
             return WebInspector.Resource.ResponseSource.DiskCache;
         default:
-            console.error("Unknown response source type: ", source);
+            console.error("Unknown response source type", source);
             return WebInspector.Resource.ResponseSource.Unknown;
         }
     }
 
+    static networkPriorityFromPayload(priority)
+    {
+        switch (priority) {
+        case NetworkAgent.MetricsPriority.Low:
+            return WebInspector.Resource.NetworkPriority.Low;
+        case NetworkAgent.MetricsPriority.Medium:
+            return WebInspector.Resource.NetworkPriority.Medium;
+        case NetworkAgent.MetricsPriority.High:
+            return WebInspector.Resource.NetworkPriority.High;
+        default:
+            console.error("Unknown metrics priority", priority);
+            return WebInspector.Resource.NetworkPriority.Unknown;
+        }
+    }
+
+    static connectionIdentifierFromPayload(connectionIdentifier)
+    {
+        // Map backend connection identifiers to an easier to read number.
+        if (!WebInspector.Resource.connectionIdentifierMap) {
+            WebInspector.Resource.connectionIdentifierMap = new Map;
+            WebInspector.Resource.nextConnectionIdentifier = 1;
+        }
+
+        let id = WebInspector.Resource.connectionIdentifierMap.get(connectionIdentifier);
+        if (id)
+            return id;
+
+        id = WebInspector.Resource.nextConnectionIdentifier++;
+        WebInspector.Resource.connectionIdentifierMap.set(connectionIdentifier, id);
+        return id;
+    }
+
     // Public
 
     get target() { return this._target; }
@@ -165,6 +201,10 @@
     get statusText() { return this._statusText; }
     get responseSource() { return this._responseSource; }
     get timingData() { return this._timingData; }
+    get protocol() { return this._protocol; }
+    get priority() { return this._priority; }
+    get remoteAddress() { return this._remoteAddress; }
+    get connectionIdentifier() { return this._connectionIdentifier; }
 
     get url()
     {
@@ -520,6 +560,18 @@
         this.dispatchEventToListeners(WebInspector.Resource.Event.TimestampsDidChange);
     }
 
+    updateWithMetrics(metrics)
+    {
+        if (metrics.protocol)
+            this._protocol = metrics.protocol;
+        if (metrics.priority)
+            this._priority = WebInspector.Resource.networkPriorityFromPayload(metrics.priority);
+        if (metrics.remoteAddress)
+            this._remoteAddress = metrics.remoteAddress;
+        if (metrics.connectionIdentifier)
+            this._connectionIdentifier = WebInspector.Resource.connectionIdentifierFromPayload(metrics.connectionIdentifier);
+    }
+
     canRequestContent()
     {
         return this._finished;
@@ -799,6 +851,13 @@
     DiskCache: Symbol("disk-cache"),
 };
 
+WebInspector.Resource.NetworkPriority = {
+    Unknown: Symbol("unknown"),
+    Low: Symbol("low"),
+    Medium: Symbol("medium"),
+    High: Symbol("high"),
+};
+
 // This MIME Type map is private, use WebInspector.Resource.typeFromMIMEType().
 WebInspector.Resource._mimeTypeMap = {
     "text/html": WebInspector.Resource.Type.Document,

Modified: trunk/Source/WebInspectorUI/UserInterface/Protocol/NetworkObserver.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/UserInterface/Protocol/NetworkObserver.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/NetworkObserver.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -48,9 +48,9 @@
         WebInspector.frameResourceManager.resourceRequestDidReceiveData(requestId, dataLength, encodedDataLength, timestamp);
     }
 
-    loadingFinished(requestId, timestamp, sourceMapURL)
+    loadingFinished(requestId, timestamp, sourceMapURL, metrics)
     {
-        WebInspector.frameResourceManager.resourceRequestDidFinishLoading(requestId, timestamp, sourceMapURL);
+        WebInspector.frameResourceManager.resourceRequestDidFinishLoading(requestId, timestamp, sourceMapURL, metrics);
     }
 
     loadingFailed(requestId, timestamp, errorText, canceled)

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/DataGrid.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/UserInterface/Views/DataGrid.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/DataGrid.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -37,7 +37,7 @@
         this._sortColumnIdentifierSetting = null;
         this._sortOrder = WebInspector.DataGrid.SortOrder.Indeterminate;
         this._sortOrderSetting = null;
-        this._hiddenColumnSetting = null;
+        this._columnVisibilitySetting = null;
         this._columnChooserEnabled = false;
         this._headerVisible = true;
 
@@ -362,7 +362,7 @@
 
         this._sortColumnIdentifierSetting = new WebInspector.Setting(this._settingsIdentifier + "-sort", this._sortColumnIdentifier);
         this._sortOrderSetting = new WebInspector.Setting(this._settingsIdentifier + "-sort-order", this._sortOrder);
-        this._hiddenColumnSetting = new WebInspector.Setting(this._settingsIdentifier + "-hidden-columns", []);
+        this._columnVisibilitySetting = new WebInspector.Setting(this._settingsIdentifier + "-column-visibility", {});
 
         if (!this.columns)
             return;
@@ -372,8 +372,11 @@
             this.sortOrder = this._sortOrderSetting.value;
         }
 
-        for (let columnIdentifier of this._hiddenColumnSetting.value)
-            this.setColumnVisible(columnIdentifier, false);
+        let visibilitySettings = this._columnVisibilitySetting.value;
+        for (let columnIdentifier in visibilitySettings) {
+            let visible = visibilitySettings[columnIdentifier];
+            this.setColumnVisible(columnIdentifier, visible);
+        }
     }
 
     _updateScrollListeners()
@@ -919,14 +922,12 @@
         column.element.style.width = visible ? column.width : 0;
         column.hidden = !visible;
 
-        if (this._hiddenColumnSetting) {
-            let hiddenColumns = this._hiddenColumnSetting.value.slice();
-            if (column.hidden)
-                hiddenColumns.push(columnIdentifier);
-            else
-                hiddenColumns.remove(columnIdentifier);
-
-            this._hiddenColumnSetting.value = hiddenColumns;
+        if (this._columnVisibilitySetting) {
+            if (this._columnVisibilitySetting.value[columnIdentifier] !== visible) {
+                let copy = Object.shallowCopy(this._columnVisibilitySetting.value);
+                copy[columnIdentifier] = visible;
+                this._columnVisibilitySetting.value = copy;
+            }
         }
 
         this._columnWidthsInitialized = false;

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -39,7 +39,7 @@
         this._contentTreeOutline = this._networkSidebarPanel.contentTreeOutline;
         this._contentTreeOutline.addEventListener(WebInspector.TreeOutline.Event.SelectionDidChange, this._treeSelectionDidChange, this);
 
-        var columns = {domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}, graph: {}};
+        let columns = {domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, protocol: {}, priority: {}, remoteAddress: {}, connectionIdentifier: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}, graph: {}};
 
         columns.domain.title = WebInspector.UIString("Domain");
         columns.domain.width = "10%";
@@ -59,6 +59,23 @@
         columns.cached.title = WebInspector.UIString("Cached");
         columns.cached.width = "8%";
 
+        columns.protocol.title = WebInspector.UIString("Protocol");
+        columns.protocol.width = "5%";
+        columns.protocol.hidden = true;
+
+        columns.priority.title = WebInspector.UIString("Priority");
+        columns.priority.width = "5%";
+        columns.priority.hidden = true;
+
+        columns.remoteAddress.title = WebInspector.UIString("Remote Address");
+        columns.remoteAddress.width = "8%";
+        columns.remoteAddress.hidden = true;
+
+        columns.connectionIdentifier.title = WebInspector.UIString("Connection");
+        columns.connectionIdentifier.width = "5%";
+        columns.connectionIdentifier.hidden = true;
+        columns.connectionIdentifier.aligned = "right";
+
         columns.size.title = WebInspector.UIString("Size");
         columns.size.width = "6%";
         columns.size.aligned = "right";
@@ -79,7 +96,7 @@
         columns.duration.width = "9%";
         columns.duration.aligned = "right";
 
-        for (var column in columns)
+        for (let column in columns)
             columns[column].sortable = true;
 
         this._timelineRuler = new WebInspector.TimelineRuler;
@@ -90,6 +107,14 @@
         columns.graph.headerView = this._timelineRuler;
         columns.graph.sortable = false;
 
+        // COMPATIBILITY(iOS 10.3): Network load metrics were not previously available.
+        if (!NetworkAgent.hasEventParameter("loadingFinished", "metrics")) {
+            delete columns.protocol;
+            delete columns.priority;
+            delete columns.remoteAddress;
+            delete columns.connectionIdentifier;
+        }
+
         this._dataGrid = new WebInspector.TimelineDataGrid(columns, this._contentTreeOutline);
         this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
         this._dataGrid.sortColumnIdentifier = "requestSent";
@@ -99,7 +124,7 @@
         this.element.classList.add("network-grid");
         this.addSubview(this._dataGrid);
 
-        var networkTimeline = WebInspector.timelineManager.persistentNetworkTimeline;
+        let networkTimeline = WebInspector.timelineManager.persistentNetworkTimeline;
         networkTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this);
         networkTimeline.addEventListener(WebInspector.Timeline.Event.Reset, this._networkTimelineReset, this);
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -31,7 +31,7 @@
 
         console.assert(timeline.type === WebInspector.TimelineRecord.Type.Network);
 
-        let columns = {name: {}, domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}, graph: {}};
+        let columns = {name: {}, domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, protocol: {}, priority: {}, remoteAddress: {}, connectionIdentifier: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}, graph: {}};
 
         columns.name.title = WebInspector.UIString("Name");
         columns.name.icon = true;
@@ -44,9 +44,9 @@
         columns.type.title = WebInspector.UIString("Type");
         columns.type.width = "7%";
 
-        var typeToLabelMap = new Map;
-        for (var key in WebInspector.Resource.Type) {
-            var value = WebInspector.Resource.Type[key];
+        let typeToLabelMap = new Map;
+        for (let key in WebInspector.Resource.Type) {
+            let value = WebInspector.Resource.Type[key];
             typeToLabelMap.set(value, WebInspector.Resource.displayNameForType(value, true));
         }
 
@@ -65,6 +65,23 @@
         columns.cached.title = WebInspector.UIString("Cached");
         columns.cached.width = "6%";
 
+        columns.protocol.title = WebInspector.UIString("Protocol");
+        columns.protocol.width = "5%";
+        columns.protocol.hidden = true;
+
+        columns.priority.title = WebInspector.UIString("Priority");
+        columns.priority.width = "5%";
+        columns.priority.hidden = true;
+
+        columns.remoteAddress.title = WebInspector.UIString("Remote Address");
+        columns.remoteAddress.width = "8%";
+        columns.remoteAddress.hidden = true;
+
+        columns.connectionIdentifier.title = WebInspector.UIString("Connection");
+        columns.connectionIdentifier.width = "5%";
+        columns.connectionIdentifier.hidden = true;
+        columns.connectionIdentifier.aligned = "right";
+
         columns.size.title = WebInspector.UIString("Size");
         columns.size.width = "6%";
         columns.size.aligned = "right";
@@ -85,7 +102,7 @@
         columns.duration.width = "9%";
         columns.duration.aligned = "right";
 
-        for (var column in columns)
+        for (let column in columns)
             columns[column].sortable = true;
 
         this._timelineRuler = new WebInspector.TimelineRuler;
@@ -96,6 +113,14 @@
         columns.graph.headerView = this._timelineRuler;
         columns.graph.sortable = false;
 
+        // COMPATIBILITY(iOS 10.3): Network load metrics were not previously available.
+        if (!NetworkAgent.hasEventParameter("loadingFinished", "metrics")) {
+            delete columns.protocol;
+            delete columns.priority;
+            delete columns.remoteAddress;
+            delete columns.connectionIdentifier;
+        }
+
         this._dataGrid = new WebInspector.TimelineDataGrid(columns);
         this._dataGrid.sortDelegate = this;
         this._dataGrid.sortColumnIdentifier = "requestSent";

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceDetailsSidebarPanel.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceDetailsSidebarPanel.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceDetailsSidebarPanel.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -68,6 +68,8 @@
         this._requestDataSection = new WebInspector.DetailsSection("resource-request-data", WebInspector.UIString("Request Data"));
 
         this._requestMethodRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Method"));
+        this._protocolRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Protocol"));
+        this._priorityRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Priority"));
         this._cachedRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Cached"));
 
         this._statusTextRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Status"));
@@ -80,10 +82,10 @@
         this._compressedRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Compressed"));
         this._compressionRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Compression"));
 
-        var requestGroup = new WebInspector.DetailsSectionGroup([this._requestMethodRow, this._cachedRow]);
-        var statusGroup = new WebInspector.DetailsSectionGroup([this._statusTextRow, this._statusCodeRow]);
-        var sizeGroup = new WebInspector.DetailsSectionGroup([this._encodedSizeRow, this._decodedSizeRow, this._transferSizeRow]);
-        var compressionGroup = new WebInspector.DetailsSectionGroup([this._compressedRow, this._compressionRow]);
+        let requestGroup = new WebInspector.DetailsSectionGroup([this._requestMethodRow, this._protocolRow, this._priorityRow, this._cachedRow]);
+        let statusGroup = new WebInspector.DetailsSectionGroup([this._statusTextRow, this._statusCodeRow]);
+        let sizeGroup = new WebInspector.DetailsSectionGroup([this._encodedSizeRow, this._decodedSizeRow, this._transferSizeRow]);
+        let compressionGroup = new WebInspector.DetailsSectionGroup([this._compressedRow, this._compressionRow]);
 
         this._requestAndResponseSection = new WebInspector.DetailsSection("resource-request-response", WebInspector.UIString("Request & Response"), [requestGroup, statusGroup, sizeGroup, compressionGroup]);
 
@@ -290,20 +292,39 @@
 
     _refreshRequestAndResponse()
     {
-        var resource = this._resource;
-        if (!resource)
+        if (!this._resource)
             return;
 
         // If we don't have a value, we set an em-dash to keep the row from hiding.
         // This keeps the UI from shifting around as data comes in.
 
-        this._requestMethodRow.value = resource.requestMethod || emDash;
+        this._requestMethodRow.value = this._resource.requestMethod || emDash;
 
-        this._cachedRow.value = resource.cached ? WebInspector.UIString("Yes") : WebInspector.UIString("No");
+        // COMPATIBILITY(iOS 10.3): Network load metrics were not previously available.
+        if (NetworkAgent.hasEventParameter("loadingFinished", "metrics")) {
+            this._protocolRow.value = this._resource.protocol || emDash;
 
-        this._statusCodeRow.value = resource.statusCode || emDash;
-        this._statusTextRow.value = resource.statusText || emDash;
+            switch (this._resource.priority) {
+            case WebInspector.Resource.NetworkPriority.Low:
+                this._priorityRow.value = WebInspector.UIString("Low");
+                break;
+            case WebInspector.Resource.NetworkPriority.Medium:
+                this._priorityRow.value = WebInspector.UIString("Medium");
+                break;
+            case WebInspector.Resource.NetworkPriority.High:
+                this._priorityRow.value = WebInspector.UIString("High");
+                break;
+            default:
+                this._priorityRow.value = emDash;
+                break;
+            }
+        }
 
+        this._cachedRow.value = this._resource.cached ? WebInspector.UIString("Yes") : WebInspector.UIString("No");
+
+        this._statusCodeRow.value = this._resource.statusCode || emDash;
+        this._statusTextRow.value = this._resource.statusText || emDash;
+
         this._refreshResponseHeaders();
         this._refreshCompressed();
     }

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -80,6 +80,10 @@
             data.requestSent = resource.requestSentTimestamp - zeroTime;
             data.duration = resource.receiveDuration;
             data.latency = resource.latency;
+            data.protocol = resource.protocol;
+            data.priority = resource.priority;
+            data.remoteAddress = resource.remoteAddress;
+            data.connectionIdentifier = resource.connectionIdentifier;
         }
 
         data.graph = this._record.startTime;
@@ -125,6 +129,14 @@
         case "latency":
         case "duration":
             return isNaN(value) ? emDash : Number.secondsToString(value, true);
+
+        case "protocol":
+        case "remoteAddress":
+        case "connectionIdentifier":
+            return value || emDash;
+
+        case "priority":
+            return this._displayNameForPriority(value);
         }
 
         return super.createCellContent(columnIdentifier, cell);
@@ -188,6 +200,20 @@
 
     // Private
 
+    _displayNameForPriority(priority)
+    {
+        switch (priority) {
+        case WebInspector.Resource.NetworkPriority.Low:
+            return WebInspector.UIString("Low");
+        case WebInspector.Resource.NetworkPriority.Medium:
+            return WebInspector.UIString("Medium");
+        case WebInspector.Resource.NetworkPriority.High:
+            return WebInspector.UIString("High");
+        }
+
+        return emDash;
+    }
+
     _createNameCellDocumentFragment()
     {
         let fragment = document.createDocumentFragment();
@@ -226,7 +252,7 @@
 
         let responseSource = this._resource.responseSource;
         if (responseSource === WebInspector.Resource.ResponseSource.MemoryCache || responseSource === WebInspector.Resource.ResponseSource.DiskCache) {
-            console.assert(this._resource.cached, "This resource has a cache responseSource it should also be marked as cached", resource);
+            console.assert(this._resource.cached, "This resource has a cache responseSource it should also be marked as cached", this._resource);
             let span = document.createElement("span");
             let cacheType = document.createElement("span");
             cacheType.classList = "cache-type";

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGridNode.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGridNode.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGridNode.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -226,9 +226,12 @@
         if (!this.revealed)
             return;
 
-        var secondsPerPixel = this._graphDataSource.secondsPerPixel;
-        console.assert(isFinite(secondsPerPixel) && secondsPerPixel > 0);
+        let secondsPerPixel = this._graphDataSource.secondsPerPixel;
+        if (isNaN(secondsPerPixel))
+            return;
 
+        console.assert(secondsPerPixel > 0);
+
         var recordBarIndex = 0;
 
         function createBar(records, renderMode)

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordBar.js (213681 => 213682)


--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordBar.js	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordBar.js	2017-03-09 23:44:12 UTC (rev 213682)
@@ -231,6 +231,9 @@
 
     refresh(graphDataSource)
     {
+        if (isNaN(graphDataSource.secondsPerPixel))
+            return;
+
         console.assert(graphDataSource.zeroTime);
         console.assert(graphDataSource.startTime);
         console.assert(graphDataSource.currentTime);

Modified: trunk/Source/WebKit2/ChangeLog (213681 => 213682)


--- trunk/Source/WebKit2/ChangeLog	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebKit2/ChangeLog	2017-03-09 23:44:12 UTC (rev 213682)
@@ -1,3 +1,17 @@
+2017-03-09  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Show HTTP protocol version and other Network Load Metrics (IP Address, Priority, Connection ID)
+        https://bugs.webkit.org/show_bug.cgi?id=29687
+        <rdar://problem/19281586>
+
+        Reviewed by Matt Baker and Brian Burg.
+
+        * NetworkProcess/cocoa/NetworkSessionCocoa.mm:
+        (toNetworkLoadPriority):
+        (-[WKNetworkSessionDelegate URLSession:task:didFinishCollectingMetrics:]):
+        * Shared/WebCoreArgumentCoders.h:
+        Additional optional metrics on NetworkLoadMetrics.
+
 2017-03-09  Daniel Bates  <[email protected]>
 
         Guard Credential Management implementation behind a runtime enabled feature flag

Modified: trunk/Source/WebKit2/NetworkProcess/cocoa/NetworkSessionCocoa.mm (213681 => 213682)


--- trunk/Source/WebKit2/NetworkProcess/cocoa/NetworkSessionCocoa.mm	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebKit2/NetworkProcess/cocoa/NetworkSessionCocoa.mm	2017-03-09 23:44:12 UTC (rev 213682)
@@ -80,6 +80,15 @@
     }
 }
 
+static WebCore::NetworkLoadPriority toNetworkLoadPriority(float priority)
+{
+    if (priority <= NSURLSessionTaskPriorityLow)
+        return WebCore::NetworkLoadPriority::Low;
+    if (priority >= NSURLSessionTaskPriorityHigh)
+        return WebCore::NetworkLoadPriority::High;
+    return WebCore::NetworkLoadPriority::Medium;
+}
+
 @interface WKNetworkSessionDelegate : NSObject <NSURLSessionDataDelegate> {
     RefPtr<WebKit::NetworkSessionCocoa> _session;
     bool _withCredentials;
@@ -290,7 +299,13 @@
         networkLoadMetrics.responseStart = Seconds(responseStartInterval);
         networkLoadMetrics.responseEnd = Seconds(responseEndInterval);
         networkLoadMetrics.markComplete();
+
         networkLoadMetrics.protocol = String(m.networkProtocolName);
+        networkLoadMetrics.priority = toNetworkLoadPriority(task.priority);
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000)
+        networkLoadMetrics.remoteAddress = String(m._remoteAddressAndPort);
+        networkLoadMetrics.connectionIdentifier = String([m._connectionIdentifier UUIDString]);
+#endif
     }
 }
 

Modified: trunk/Source/WebKit2/Shared/WebCoreArgumentCoders.h (213681 => 213682)


--- trunk/Source/WebKit2/Shared/WebCoreArgumentCoders.h	2017-03-09 23:21:19 UTC (rev 213681)
+++ trunk/Source/WebKit2/Shared/WebCoreArgumentCoders.h	2017-03-09 23:44:12 UTC (rev 213682)
@@ -30,6 +30,7 @@
 #include <WebCore/DiagnosticLoggingClient.h>
 #include <WebCore/FrameLoaderTypes.h>
 #include <WebCore/IndexedDB.h>
+#include <WebCore/NetworkLoadMetrics.h>
 #include <WebCore/PaymentHeaders.h>
 #include <WebCore/ScrollSnapOffsetsInfo.h>
 
@@ -678,6 +679,15 @@
     >;
 };
 
+template<> struct EnumTraits<WebCore::NetworkLoadPriority> {
+    using values = EnumValues<
+        WebCore::NetworkLoadPriority,
+        WebCore::NetworkLoadPriority::Low,
+        WebCore::NetworkLoadPriority::Medium,
+        WebCore::NetworkLoadPriority::High
+    >;
+};
+
 #if ENABLE(INDEXED_DATABASE)
 template<> struct EnumTraits<WebCore::IndexedDB::GetAllType> {
     using values = EnumValues<
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to