Title: [236995] trunk
Revision
236995
Author
[email protected]
Date
2018-10-09 19:49:52 -0700 (Tue, 09 Oct 2018)

Log Message

Web Inspector: show redirect requests in Network and Timelines tabs
https://bugs.webkit.org/show_bug.cgi?id=150005
<rdar://problem/5378164>

Reviewed by Joseph Pecoraro.

Source/_javascript_Core:

* inspector/protocol/Network.json:
Add missing fields to `ResourceTiming`.

Source/WebCore:

Updated existing test http/tests/inspector/network/resource-timing.html.

* inspector/agents/InspectorNetworkAgent.cpp:
(WebCore::InspectorNetworkAgent::buildObjectForTiming):
(WebCore::InspectorNetworkAgent::didFinishLoading):
Add missing fields for `Network.types.ResourceTiming`.

Source/WebInspectorUI:

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Views/Variables.css:
* UserInterface/Main.html:
* UserInterface/Test.html:

* UserInterface/Controllers/NetworkManager.js:
(WI.NetworkManager.prototype.resourceRequestWillBeSent):

* UserInterface/Models/Resource.js:
(WI.Resource):
(WI.Resource.prototype.get redirects): Added.
(WI.Resource.prototype.get lastRedirectReceivedTimestamp):
(WI.Resource.prototype.updateForRedirectResponse):
Save each redirect in an array instead of just remembering the last timestamp.

* UserInterface/Models/ResourceTimingData.js:
(WI.ResourceTimingData):
(WI.ResourceTimingData.fromPayload.offsetToTimestamp):
(WI.ResourceTimingData.fromPayload):
(WI.ResourceTimingData.prototype.get redirectStart): Added.
(WI.ResourceTimingData.prototype.get redirectEnd): Added.
(WI.ResourceTimingData.prototype.get fetchStart): Added.
Add missing fields for `Network.types.ResourceTiming`.

* UserInterface/Models/Redirect.js: Added.
(WI.Redirect):
(WI.Redirect.prototype.get url):
(WI.Redirect.prototype.get requestMethod):
(WI.Redirect.prototype.get requestHeaders):
(WI.Redirect.prototype.get responseStatusCode):
(WI.Redirect.prototype.get responseStatusText):
(WI.Redirect.prototype.get responseHeaders):
(WI.Redirect.prototype.get timestamp):
(WI.Redirect.prototype.get urlComponents):

* UserInterface/Views/ResourceHeadersContentView.js:
(WI.ResourceHeadersContentView):
(WI.ResourceHeadersContentView.prototype.initialLayout):
(WI.ResourceHeadersContentView.prototype.layout):
(WI.ResourceHeadersContentView.prototype._refreshRedirectHeadersSections): Added.
(WI.ResourceHeadersContentView.prototype._resourceRequestHeadersDidChange):
* UserInterface/Views/ResourceHeadersContentView.css:
(body[dir] .resource-headers > section.summary > .details): Added.
(body[dir] .resource-headers > section:matches(.redirect, .headers) > .details): Added.
(.resource-headers .details .key):
(.resource-headers .summary .key):
(body[dir] .resource-headers > section > .details): Deleted.
(body[dir] .resource-headers > section.headers > .details): Deleted.
(.resource-headers .value): Deleted.
Add a request/response header section for each redirect.

* UserInterface/Views/NetworkTableContentView.js:
(WI.NetworkTableContentView.prototype._populateWaterfallGraph.appendBlock):
(WI.NetworkTableContentView.prototype._populateWaterfallGraph):
(WI.NetworkTableContentView.prototype._checkURLFilterAgainstResource):
(WI.NetworkTableContentView.prototype._waterfallPopoverContentForResource):
* UserInterface/Views/NetworkTableContentView.css:
(.waterfall .block.redirect): Added.
(.waterfall .block.queue):
* UserInterface/Views/ResourceTimelineDataGridNode.js:
(WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar):
* UserInterface/Views/ResourceTimingBreakdownView.js:
(WI.ResourceTimingBreakdownView.prototype.initialLayout):
Add timeline/waterfall entries for total redirect time.

LayoutTests:

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

* http/tests/inspector/network/resources/delay.php: Added.
* http/tests/inspector/network/resources/redirect.php: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (236994 => 236995)


--- trunk/LayoutTests/ChangeLog	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/LayoutTests/ChangeLog	2018-10-10 02:49:52 UTC (rev 236995)
@@ -1,3 +1,17 @@
+2018-10-09  Devin Rousso  <[email protected]>
+
+        Web Inspector: show redirect requests in Network and Timelines tabs
+        https://bugs.webkit.org/show_bug.cgi?id=150005
+        <rdar://problem/5378164>
+
+        Reviewed by Joseph Pecoraro.
+
+        * http/tests/inspector/network/resource-timing-expected.txt:
+        * http/tests/inspector/network/resource-timing.html:
+
+        * http/tests/inspector/network/resources/delay.php: Added.
+        * http/tests/inspector/network/resources/redirect.php: Added.
+
 2018-10-09  Said Abou-Hallawa  <[email protected]>
 
         REGRESSION(r234620): SVGLangSpace::svgAttributeChanged() should invalidate the renderer of the SVGGeometryElement descendant only

Modified: trunk/LayoutTests/http/tests/inspector/network/resource-timing-expected.txt (236994 => 236995)


--- trunk/LayoutTests/http/tests/inspector/network/resource-timing-expected.txt	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/LayoutTests/http/tests/inspector/network/resource-timing-expected.txt	2018-10-10 02:49:52 UTC (rev 236995)
@@ -1,13 +1,14 @@
 Tests that a resource has timing information.
 
 
-== Running test suite: ResourceTimingData
--- Running test case: CheckResourceTimingInformationForResource
+== Running test suite: Resource.TimingData
+-- Running test case: Resource.TimingData.Basic
 PASS: Resource should be created.
 PASS: Added Resource received a response.
 PASS: Added Resource did finish loading.
 PASS: Newly added resource should have a resource timing model.
 PASS: Resource should have a start time.
+PASS: Resource should have a fetch start time.
 PASS: Resource should have a request start time.
 PASS: Resource should have a response start time.
 PASS: domainLookupStart and domainLookupEnd should both be NaN or a number.
@@ -17,3 +18,9 @@
 PASS: responseStart should come after requestStart.
 PASS: responseEnd should come after responseStart.
 
+-- Running test case: Resource.TimingData.Redirect
+PASS: Start time should be before redirect start time.
+PASS: Redirect start time should be before redirect end time.
+PASS: Redirect duration should be at least a few milliseconds.
+PASS: Redirect end time should be before fetch start time.
+

Modified: trunk/LayoutTests/http/tests/inspector/network/resource-timing.html (236994 => 236995)


--- trunk/LayoutTests/http/tests/inspector/network/resource-timing.html	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/LayoutTests/http/tests/inspector/network/resource-timing.html	2018-10-10 02:49:52 UTC (rev 236995)
@@ -4,18 +4,24 @@
 <meta charset="utf-8">
 <script src=""
 <script>
-function createRequest() {
+function createImageRequest() {
     let img = document.createElement("img");
     img.src = ""
     document.body.appendChild(img);
 }
 
+function createRedirectRequest(delay) {
+    let iframe = document.createElement("iframe");
+    iframe.src = ""
+    document.body.appendChild(iframe);
+}
+
 function test()
 {
-    let suite = InspectorTest.createAsyncSuite("ResourceTimingData");
+    let suite = InspectorTest.createAsyncSuite("Resource.TimingData");
 
     suite.addTestCase({
-        name: "CheckResourceTimingInformationForResource",
+        name: "Resource.TimingData.Basic",
         description: "Check if a resource has timing information.",
         test(resolve, reject) {
             Promise.all([
@@ -32,24 +38,52 @@
 
                 let timingData = resource.timingData;
                 InspectorTest.expectThat(timingData instanceof WI.ResourceTimingData, "Newly added resource should have a resource timing model.");
-                InspectorTest.expectThat(timingData.startTime > 0, "Resource should have a start time.");
-                InspectorTest.expectThat(timingData.requestStart > 0, "Resource should have a request start time.");
-                InspectorTest.expectThat(timingData.responseStart > 0, "Resource should have a response start time.");
+                InspectorTest.expectGreaterThan(timingData.startTime, 0, "Resource should have a start time.");
+                InspectorTest.expectGreaterThan(timingData.fetchStart, 0, "Resource should have a fetch start time.");
+                InspectorTest.expectGreaterThan(timingData.requestStart, 0, "Resource should have a request start time.");
+                InspectorTest.expectGreaterThan(timingData.responseStart, 0, "Resource should have a response start time.");
 
                 InspectorTest.expectThat(typeof timingData.domainLookupStart === "number" && typeof timingData.domainLookupEnd === "number", "domainLookupStart and domainLookupEnd should both be NaN or a number.");
                 InspectorTest.expectThat(typeof timingData.connectStart === "number" && typeof timingData.connectStart === "number", "connectStart and connectEnd should both be NaN or a number.");
 
-                InspectorTest.expectThat(timingData.startTime <= timingData.requestStart, "requestStart should come after startTime.");
+                InspectorTest.expectLessThanOrEqual(timingData.startTime, timingData.requestStart, "requestStart should come after startTime.");
                 InspectorTest.expectThat(isNaN(timingData.secureConnectionStart) || timingData.connectStart <= timingData.secureConnectionStart, "A secure connection should be reused or secureConnectionStart should come after connectStart.");
-                InspectorTest.expectThat(timingData.requestStart <= timingData.responseStart, "responseStart should come after requestStart.");
-                InspectorTest.expectThat(timingData.responseStart <= timingData.responseEnd, "responseEnd should come after responseStart.");
+                InspectorTest.expectLessThanOrEqual(timingData.requestStart, timingData.responseStart, "responseStart should come after requestStart.");
+                InspectorTest.expectLessThanOrEqual(timingData.responseStart, timingData.responseEnd, "responseEnd should come after responseStart.");
             })
             .then(resolve, reject);
 
-            InspectorTest.evaluateInPage("createRequest()");
+            InspectorTest.evaluateInPage(`createImageRequest()`);
         }
     });
 
+    suite.addTestCase({
+        name: "Resource.TimingData.Redirect",
+        description: "Check if a redirected resource has timing information.",
+        test(resolve, reject) {
+            const delay = 100;
+
+            WI.Resource.awaitEvent(WI.Resource.Event.ResponseReceived)
+            .then((event) => {
+                let resource = event.target;
+
+                let timingData = resource.timingData;
+                InspectorTest.assert(timingData.startTime >= 0, "Resource should have a start time.");
+                InspectorTest.assert(timingData.redirectStart >= 0, "Resource should have a redirect start time.");
+                InspectorTest.assert(timingData.redirectEnd >= 0, "Resource should have a redirect end time.");
+                InspectorTest.assert(timingData.fetchStart >= 0, "Resource should have a fetch start time.");
+
+                InspectorTest.expectLessThanOrEqual(timingData.startTime, timingData.redirectStart, "Start time should be before redirect start time.");
+                InspectorTest.expectLessThan(timingData.redirectStart, timingData.redirectEnd, "Redirect start time should be before redirect end time.");
+                InspectorTest.expectGreaterThanOrEqual(timingData.redirectEnd - timingData.redirectStart, (delay / 2) / 1000, "Redirect duration should be at least a few milliseconds.");
+                InspectorTest.expectLessThanOrEqual(timingData.redirectEnd, timingData.fetchStart, "Redirect end time should be before fetch start time.");
+            })
+            .then(resolve, reject);
+
+            InspectorTest.evaluateInPage(`createRedirectRequest(${delay})`);
+        }
+    });
+
     suite.runTestCasesAndFinish();
 }
 </script>

Added: trunk/LayoutTests/http/tests/inspector/network/resources/delay.php (0 => 236995)


--- trunk/LayoutTests/http/tests/inspector/network/resources/delay.php	                        (rev 0)
+++ trunk/LayoutTests/http/tests/inspector/network/resources/delay.php	2018-10-10 02:49:52 UTC (rev 236995)
@@ -0,0 +1,11 @@
+<?php
+
+$delay = isset($_GET['delay']) ? intval($_GET['delay']) : 100;
+$redirect = isset($_GET['redirect']) ? intval($_GET['redirect']) : 'redirect.php';
+
+usleep($delay * 1000);
+
+header('Location: ' . $redirect);
+
+?>
+

Added: trunk/LayoutTests/http/tests/inspector/network/resources/redirect.php (0 => 236995)


--- trunk/LayoutTests/http/tests/inspector/network/resources/redirect.php	                        (rev 0)
+++ trunk/LayoutTests/http/tests/inspector/network/resources/redirect.php	2018-10-10 02:49:52 UTC (rev 236995)
@@ -0,0 +1,5 @@
+<?php
+
+echo 'Redirect';
+
+?>

Modified: trunk/Source/_javascript_Core/ChangeLog (236994 => 236995)


--- trunk/Source/_javascript_Core/ChangeLog	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-10-10 02:49:52 UTC (rev 236995)
@@ -1,3 +1,14 @@
+2018-10-09  Devin Rousso  <[email protected]>
+
+        Web Inspector: show redirect requests in Network and Timelines tabs
+        https://bugs.webkit.org/show_bug.cgi?id=150005
+        <rdar://problem/5378164>
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/protocol/Network.json:
+        Add missing fields to `ResourceTiming`.
+
 2018-10-09  Claudio Saavedra  <[email protected]>
 
         [WPE] Explicitly link against gmodule where used

Modified: trunk/Source/_javascript_Core/inspector/protocol/Network.json (236994 => 236995)


--- trunk/Source/_javascript_Core/inspector/protocol/Network.json	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/_javascript_Core/inspector/protocol/Network.json	2018-10-10 02:49:52 UTC (rev 236995)
@@ -38,14 +38,18 @@
             "type": "object",
             "description": "Timing information for the request.",
             "properties": [
-                { "name": "startTime", "type": "number", "description": "Timing's startTime is a baseline in seconds, while the other numbers are ticks in milliseconds relatively to this." },
-                { "name": "domainLookupStart", "type": "number", "description": "Started DNS address resolve." },
-                { "name": "domainLookupEnd", "type": "number", "description": "Finished DNS address resolve." },
-                { "name": "connectStart", "type": "number", "description": "Started connecting to the remote host." },
-                { "name": "connectEnd", "type": "number", "description": "Connected to the remote host." },
-                { "name": "secureConnectionStart", "type": "number", "description": "Started SSL handshake." },
-                { "name": "requestStart", "type": "number", "description": "Started sending request." },
-                { "name": "responseStart", "type": "number", "description": "Started receiving response headers." }
+                { "name": "startTime", "$ref": "Timestamp", "description": "Request is initiated" },
+                { "name": "redirectStart", "$ref": "Timestamp", "description": "Started redirect resolution." },
+                { "name": "redirectEnd", "$ref": "Timestamp", "description": "Finished redirect resolution." },
+                { "name": "fetchStart", "$ref": "Timestamp", "description": "Resource fetching started." },
+                { "name": "domainLookupStart", "type": "number", "description": "Started DNS address resolve in milliseconds relative to fetchStart." },
+                { "name": "domainLookupEnd", "type": "number", "description": "Finished DNS address resolve in milliseconds relative to fetchStart." },
+                { "name": "connectStart", "type": "number", "description": "Started connecting to the remote host in milliseconds relative to fetchStart." },
+                { "name": "connectEnd", "type": "number", "description": "Connected to the remote host in milliseconds relative to fetchStart." },
+                { "name": "secureConnectionStart", "type": "number", "description": "Started SSL handshake in milliseconds relative to fetchStart." },
+                { "name": "requestStart", "type": "number", "description": "Started sending request in milliseconds relative to fetchStart." },
+                { "name": "responseStart", "type": "number", "description": "Started receiving response headers in milliseconds relative to fetchStart." },
+                { "name": "responseEnd", "type": "number", "description": "Finished receiving response headers in milliseconds relative to fetchStart." }
             ]
         },
         {

Modified: trunk/Source/WebCore/ChangeLog (236994 => 236995)


--- trunk/Source/WebCore/ChangeLog	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebCore/ChangeLog	2018-10-10 02:49:52 UTC (rev 236995)
@@ -1,3 +1,18 @@
+2018-10-09  Devin Rousso  <[email protected]>
+
+        Web Inspector: show redirect requests in Network and Timelines tabs
+        https://bugs.webkit.org/show_bug.cgi?id=150005
+        <rdar://problem/5378164>
+
+        Reviewed by Joseph Pecoraro.
+
+        Updated existing test http/tests/inspector/network/resource-timing.html.
+
+        * inspector/agents/InspectorNetworkAgent.cpp:
+        (WebCore::InspectorNetworkAgent::buildObjectForTiming):
+        (WebCore::InspectorNetworkAgent::didFinishLoading):
+        Add missing fields for `Network.types.ResourceTiming`.
+
 2018-10-09  Said Abou-Hallawa  <[email protected]>
 
         REGRESSION(r234620): SVGLangSpace::svgAttributeChanged() should invalidate the renderer of the SVGGeometryElement descendant only

Modified: trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp (236994 => 236995)


--- trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp	2018-10-10 02:49:52 UTC (rev 236995)
@@ -197,11 +197,17 @@
 
 Ref<Inspector::Protocol::Network::ResourceTiming> InspectorNetworkAgent::buildObjectForTiming(const NetworkLoadMetrics& timing, ResourceLoader& resourceLoader)
 {
-    MonotonicTime startTime = resourceLoader.loadTiming().startTime();
-    Seconds startTimeInInspector = m_environment.executionStopwatch()->elapsedTimeSince(startTime);
+    auto& loadTiming = resourceLoader.loadTiming();
 
+    auto elapsedTimeSince = [&] (const MonotonicTime& time) {
+        return m_environment.executionStopwatch()->elapsedTimeSince(time).seconds();
+    };
+
     return Inspector::Protocol::Network::ResourceTiming::create()
-        .setStartTime(startTimeInInspector.seconds())
+        .setStartTime(elapsedTimeSince(loadTiming.startTime()))
+        .setRedirectStart(elapsedTimeSince(loadTiming.redirectStart()))
+        .setRedirectEnd(elapsedTimeSince(loadTiming.redirectEnd()))
+        .setFetchStart(elapsedTimeSince(loadTiming.fetchStart()))
         .setDomainLookupStart(timing.domainLookupStart.milliseconds())
         .setDomainLookupEnd(timing.domainLookupEnd.milliseconds())
         .setConnectStart(timing.connectStart.milliseconds())
@@ -209,6 +215,7 @@
         .setSecureConnectionStart(timing.secureConnectionStart.milliseconds())
         .setRequestStart(timing.requestStart.milliseconds())
         .setResponseStart(timing.responseStart.milliseconds())
+        .setResponseEnd(timing.responseEnd.milliseconds())
         .release();
 }
 
@@ -506,9 +513,9 @@
 
     double elapsedFinishTime;
     if (resourceLoader && networkLoadMetrics.isComplete()) {
-        MonotonicTime startTime = resourceLoader->loadTiming().startTime();
-        Seconds startTimeInInspector = m_environment.executionStopwatch()->elapsedTimeSince(startTime);
-        elapsedFinishTime = (startTimeInInspector + networkLoadMetrics.responseEnd).seconds();
+        MonotonicTime fetchStart = resourceLoader->loadTiming().fetchStart();
+        Seconds fetchStartInInspector = m_environment.executionStopwatch()->elapsedTimeSince(fetchStart);
+        elapsedFinishTime = (fetchStartInInspector + networkLoadMetrics.responseEnd).seconds();
     } else
         elapsedFinishTime = timestamp();
 

Modified: trunk/Source/WebInspectorUI/ChangeLog (236994 => 236995)


--- trunk/Source/WebInspectorUI/ChangeLog	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/ChangeLog	2018-10-10 02:49:52 UTC (rev 236995)
@@ -1,5 +1,78 @@
 2018-10-09  Devin Rousso  <[email protected]>
 
+        Web Inspector: show redirect requests in Network and Timelines tabs
+        https://bugs.webkit.org/show_bug.cgi?id=150005
+        <rdar://problem/5378164>
+
+        Reviewed by Joseph Pecoraro.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Views/Variables.css:
+        * UserInterface/Main.html:
+        * UserInterface/Test.html:
+
+        * UserInterface/Controllers/NetworkManager.js:
+        (WI.NetworkManager.prototype.resourceRequestWillBeSent):
+
+        * UserInterface/Models/Resource.js:
+        (WI.Resource):
+        (WI.Resource.prototype.get redirects): Added.
+        (WI.Resource.prototype.get lastRedirectReceivedTimestamp):
+        (WI.Resource.prototype.updateForRedirectResponse):
+        Save each redirect in an array instead of just remembering the last timestamp.
+
+        * UserInterface/Models/ResourceTimingData.js:
+        (WI.ResourceTimingData):
+        (WI.ResourceTimingData.fromPayload.offsetToTimestamp):
+        (WI.ResourceTimingData.fromPayload):
+        (WI.ResourceTimingData.prototype.get redirectStart): Added.
+        (WI.ResourceTimingData.prototype.get redirectEnd): Added.
+        (WI.ResourceTimingData.prototype.get fetchStart): Added.
+        Add missing fields for `Network.types.ResourceTiming`.
+
+        * UserInterface/Models/Redirect.js: Added.
+        (WI.Redirect):
+        (WI.Redirect.prototype.get url):
+        (WI.Redirect.prototype.get requestMethod):
+        (WI.Redirect.prototype.get requestHeaders):
+        (WI.Redirect.prototype.get responseStatusCode):
+        (WI.Redirect.prototype.get responseStatusText):
+        (WI.Redirect.prototype.get responseHeaders):
+        (WI.Redirect.prototype.get timestamp):
+        (WI.Redirect.prototype.get urlComponents):
+
+        * UserInterface/Views/ResourceHeadersContentView.js:
+        (WI.ResourceHeadersContentView):
+        (WI.ResourceHeadersContentView.prototype.initialLayout):
+        (WI.ResourceHeadersContentView.prototype.layout):
+        (WI.ResourceHeadersContentView.prototype._refreshRedirectHeadersSections): Added.
+        (WI.ResourceHeadersContentView.prototype._resourceRequestHeadersDidChange):
+        * UserInterface/Views/ResourceHeadersContentView.css:
+        (body[dir] .resource-headers > section.summary > .details): Added.
+        (body[dir] .resource-headers > section:matches(.redirect, .headers) > .details): Added.
+        (.resource-headers .details .key):
+        (.resource-headers .summary .key):
+        (body[dir] .resource-headers > section > .details): Deleted.
+        (body[dir] .resource-headers > section.headers > .details): Deleted.
+        (.resource-headers .value): Deleted.
+        Add a request/response header section for each redirect.
+
+        * UserInterface/Views/NetworkTableContentView.js:
+        (WI.NetworkTableContentView.prototype._populateWaterfallGraph.appendBlock):
+        (WI.NetworkTableContentView.prototype._populateWaterfallGraph):
+        (WI.NetworkTableContentView.prototype._checkURLFilterAgainstResource):
+        (WI.NetworkTableContentView.prototype._waterfallPopoverContentForResource):
+        * UserInterface/Views/NetworkTableContentView.css:
+        (.waterfall .block.redirect): Added.
+        (.waterfall .block.queue):
+        * UserInterface/Views/ResourceTimelineDataGridNode.js:
+        (WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar):
+        * UserInterface/Views/ResourceTimingBreakdownView.js:
+        (WI.ResourceTimingBreakdownView.prototype.initialLayout):
+        Add timeline/waterfall entries for total redirect time.
+
+2018-10-09  Devin Rousso  <[email protected]>
+
         Web Inspector: Canvas Tab: grayed out Record button in navigator is nearly invisible
         https://bugs.webkit.org/show_bug.cgi?id=190365
         <rdar://problem/45097739>

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


--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2018-10-10 02:49:52 UTC (rev 236995)
@@ -654,6 +654,8 @@
 localizedStrings["Recording Timeline Data"] = "Recording Timeline Data";
 localizedStrings["Recording error: %s"] = "Recording error: %s";
 localizedStrings["Recordings"] = "Recordings";
+localizedStrings["Redirect Response"] = "Redirect Response";
+localizedStrings["Redirects"] = "Redirects";
 localizedStrings["Reference Issue"] = "Reference Issue";
 localizedStrings["Reflection"] = "Reflection";
 localizedStrings["Refresh"] = "Refresh";

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/NetworkManager.js (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/NetworkManager.js	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/NetworkManager.js	2018-10-10 02:49:52 UTC (rev 236995)
@@ -239,9 +239,10 @@
         let resource = this._resourceRequestIdentifierMap.get(requestIdentifier);
         if (resource) {
             // This is an existing request which is being redirected, update the resource.
-            console.assert(redirectResponse);
+            console.assert(resource.parentFrame.id === frameIdentifier);
+            console.assert(resource.loaderIdentifier === loaderIdentifier);
             console.assert(!targetId);
-            resource.updateForRedirectResponse(request.url, request.headers, elapsedTime);
+            resource.updateForRedirectResponse(request, redirectResponse, elapsedTime, walltime);
             return;
         }
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Main.html	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html	2018-10-10 02:49:52 UTC (rev 236995)
@@ -404,6 +404,7 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""

Added: trunk/Source/WebInspectorUI/UserInterface/Models/Redirect.js (0 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Models/Redirect.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Redirect.js	2018-10-10 02:49:52 UTC (rev 236995)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.Redirect = class Redirect
+{
+    constructor(url, requestMethod, requestHeaders, responseStatusCode, responseStatusText, responseHeaders, timestamp)
+    {
+        console.assert(typeof url ="" "string");
+        console.assert(typeof requestMethod === "string");
+        console.assert(typeof requestHeaders === "object");
+        console.assert(!isNaN(responseStatusCode));
+        console.assert(typeof responseStatusText === "string");
+        console.assert(typeof responseHeaders === "object");
+        console.assert(!isNaN(timestamp));
+
+        this._url = url;
+        this._urlComponents = null;
+        this._requestMethod = requestMethod;
+        this._requestHeaders = requestHeaders;
+        this._responseStatusCode = responseStatusCode;
+        this._responseStatusText = responseStatusText;
+        this._responseHeaders = responseHeaders;
+        this._timestamp = timestamp;
+    }
+
+    // Public
+
+    get url() { return this._url; }
+    get requestMethod() { return this._requestMethod; }
+    get requestHeaders() { return this._requestHeaders; }
+    get responseStatusCode() { return this._responseStatusCode; }
+    get responseStatusText() { return this._responseStatusText; }
+    get responseHeaders() { return this._responseHeaders; }
+    get timestamp() { return this._timestamp; }
+
+    get urlComponents()
+    {
+        if (!this._urlComponents)
+            this._urlComponents = parseURL(this._url);
+        return this._urlComponents;
+    }
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js	2018-10-10 02:49:52 UTC (rev 236995)
@@ -58,7 +58,6 @@
         this._requestSentTimestamp = requestSentTimestamp || NaN;
         this._requestSentWalltime = requestSentWalltime || NaN;
         this._responseReceivedTimestamp = NaN;
-        this._lastRedirectReceivedTimestamp = NaN;
         this._lastDataReceivedTimestamp = NaN;
         this._finishedOrFailedTimestamp = NaN;
         this._finishThenRequestContentPromise = null;
@@ -76,6 +75,7 @@
         this._remoteAddress = null;
         this._connectionIdentifier = null;
         this._target = targetId ? WI.targetManager.targetForIdentifier(targetId) : WI.mainTarget;
+        this._redirects = [];
 
         // Exact sizes if loaded over the network or cache.
         this._requestHeadersTransferSize = NaN;
@@ -319,7 +319,6 @@
     get responseHeaders() { return this._responseHeaders; }
     get requestSentTimestamp() { return this._requestSentTimestamp; }
     get requestSentWalltime() { return this._requestSentWalltime; }
-    get lastRedirectReceivedTimestamp() { return this._lastRedirectReceivedTimestamp; }
     get responseReceivedTimestamp() { return this._responseReceivedTimestamp; }
     get lastDataReceivedTimestamp() { return this._lastDataReceivedTimestamp; }
     get finishedOrFailedTimestamp() { return this._finishedOrFailedTimestamp; }
@@ -329,6 +328,7 @@
     get responseHeadersTransferSize() { return this._responseHeadersTransferSize; }
     get responseBodyTransferSize() { return this._responseBodyTransferSize; }
     get cachedResponseBodySize() { return this._cachedResponseBodySize; }
+    get redirects() { return this._redirects; }
 
     get urlComponents()
     {
@@ -467,6 +467,11 @@
         return isNaN(this._requestSentWalltime) ? null : new Date(this._requestSentWalltime * 1000);
     }
 
+    get lastRedirectReceivedTimestamp()
+    {
+        return this._redirects.length ? this._redirects.lastValue.timestamp : NaN;
+    }
+
     get firstTimestamp()
     {
         return this.timingData.startTime || this.lastRedirectReceivedTimestamp || this.responseReceivedTimestamp || this.lastDataReceivedTimestamp || this.finishedOrFailedTimestamp;
@@ -624,22 +629,23 @@
         return null;
     }
 
-    updateForRedirectResponse(url, requestHeaders, elapsedTime)
+    updateForRedirectResponse(request, response, elapsedTime, walltime)
     {
         console.assert(!this._finished);
         console.assert(!this._failed);
         console.assert(!this._canceled);
 
-        var oldURL = this._url;
+        let oldURL = this._url;
+        let oldHeaders = this._requestHeaders;
 
-        if (url)
-            this._url = url;
+        if (request.url)
+            this._url = request.url;
 
-        this._requestHeaders = requestHeaders || {};
+        this._requestHeaders = request.headers || {};
         this._requestCookies = null;
-        this._lastRedirectReceivedTimestamp = elapsedTime || NaN;
+        this._redirects.push(new WI.Redirect(oldURL, request.method, oldHeaders, response.status, response.statusText, response.headers, elapsedTime));
 
-        if (oldURL !== url) {
+        if (oldURL !== request.url) {
             // Delete the URL components so the URL is re-parsed the next time it is requested.
             this._urlComponents = null;
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/ResourceTimingData.js (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Models/ResourceTimingData.js	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/ResourceTimingData.js	2018-10-10 02:49:52 UTC (rev 236995)
@@ -29,6 +29,8 @@
     {
         data = "" || {};
 
+        console.assert(isNaN(data.startTime) || data.startTime <= data.fetchStart);
+        console.assert(isNaN(data.redirectStart) === isNaN(data.redirectEnd));
         console.assert(isNaN(data.domainLookupStart) === isNaN(data.domainLookupEnd));
         console.assert(isNaN(data.connectStart) === isNaN(data.connectEnd));
 
@@ -35,6 +37,9 @@
         this._resource = resource;
 
         this._startTime = data.startTime || NaN;
+        this._redirectStart = data.redirectStart || NaN;
+        this._redirectEnd = data.redirectEnd || NaN;
+        this._fetchStart = data.fetchStart || NaN;
         this._domainLookupStart = data.domainLookupStart || NaN;
         this._domainLookupEnd = data.domainLookupEnd || NaN;
         this._connectStart = data.connectStart || NaN;
@@ -62,12 +67,30 @@
         if (typeof payload.navigationStart === "number")
             payload = {};
 
+        // COMPATIBILITY (iOS 12.0): Resource Timing data was based on startTime, not fetchStart.
+        let startTime = payload.startTime;
+        let fetchStart = payload.fetchStart;
+        let redirectStart = payload.redirectStart;
+        let redirectEnd = payload.redirectEnd;
+
+        if (isNaN(fetchStart) || fetchStart < startTime)
+            fetchStart = startTime;
+
+        if (redirectStart < startTime || redirectStart > fetchStart || redirectStart > redirectEnd)
+            redirectStart = NaN;
+
+        if (redirectEnd < startTime || redirectEnd > fetchStart || redirectEnd < redirectStart)
+            redirectEnd = NaN;
+
         function offsetToTimestamp(offset) {
-            return offset > 0 ? payload.startTime + (offset / 1000) : NaN;
+            return offset > 0 ? fetchStart + (offset / 1000) : NaN;
         }
 
         let data = {
-            startTime: payload.startTime,
+            startTime,
+            redirectStart,
+            redirectEnd,
+            fetchStart,
             domainLookupStart: offsetToTimestamp(payload.domainLookupStart),
             domainLookupEnd: offsetToTimestamp(payload.domainLookupEnd),
             connectStart: offsetToTimestamp(payload.connectStart),
@@ -88,6 +111,9 @@
     // Public
 
     get startTime() { return this._startTime || this._resource.requestSentTimestamp; }
+    get redirectStart() { return this._redirectStart; }
+    get redirectEnd() { return this._redirectEnd; }
+    get fetchStart() { return this._fetchStart; }
     get domainLookupStart() { return this._domainLookupStart; }
     get domainLookupEnd() { return this._domainLookupEnd; }
     get connectStart() { return this._connectStart; }

Modified: trunk/Source/WebInspectorUI/UserInterface/Test.html (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Test.html	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Test.html	2018-10-10 02:49:52 UTC (rev 236995)
@@ -173,6 +173,7 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css	2018-10-10 02:49:52 UTC (rev 236995)
@@ -186,9 +186,17 @@
     height: 18px;
 }
 
+.waterfall .block.filler {
+    top: 9px;
+    height: 2px;
+    background-color: lightgrey;
+}
+
+.waterfall .block.redirect {
+    background-color: var(--network-redirect-color);
+}
+
 .waterfall .block.queue {
-    min-width: 3px;
-    -webkit-margin-start: -1px;
     background-color: var(--network-queue-color);
 }
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js	2018-10-10 02:49:52 UTC (rev 236995)
@@ -651,8 +651,8 @@
             return;
         }
 
-        let {startTime, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd} = resource.timingData;
-        if (isNaN(startTime)) {
+        let {startTime, redirectStart, redirectEnd, fetchStart, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd} = resource.timingData;
+        if (isNaN(startTime) || isNaN(responseEnd)) {
             cell.textContent = zeroWidthSpace;
             return;
         }
@@ -674,9 +674,12 @@
         let container = cell.appendChild(document.createElement("div"));
         container.className = "waterfall-container";
 
-        function appendBlock(startTime, endTime, className) {
-            let startOffset = (startTime - graphStartTime) / secondsPerPixel;
-            let width = (endTime - startTime) / secondsPerPixel;
+        function appendBlock(startTimestamp, endTimestamp, className) {
+            if (isNaN(startTimestamp) || isNaN(endTimestamp) || endTimestamp - startTimestamp <= 0)
+                return null;
+
+            let startOffset = (startTimestamp - graphStartTime) / secondsPerPixel;
+            let width = (endTimestamp - startTimestamp) / secondsPerPixel;
             let block = container.appendChild(document.createElement("div"));
             block.classList.add("block", className);
             let styleAttribute = WI.resolvedLayoutDirection() === WI.LayoutDirection.LTR ? "left" : "right";
@@ -702,16 +705,20 @@
             return;
         }
 
-        // Each component.
+        appendBlock(startTime, responseEnd, "filler");
+
+        // FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
+        appendBlock(redirectStart, redirectEnd, "redirect");
+
         if (domainLookupStart) {
-            appendBlock(startTime, domainLookupStart, "queue");
-            appendBlock(domainLookupStart, connectStart || requestStart, "dns");
+            appendBlock(fetchStart, domainLookupStart, "queue");
+            appendBlock(domainLookupStart, domainLookupEnd || connectStart || requestStart, "dns");
         } else if (connectStart)
-            appendBlock(startTime, connectStart, "queue");
+            appendBlock(fetchStart, connectStart, "queue");
         else if (requestStart)
-            appendBlock(startTime, requestStart, "queue");
+            appendBlock(fetchStart, requestStart, "queue");
         if (connectStart)
-            appendBlock(connectStart, connectEnd, "connect");
+            appendBlock(connectStart, secureConnectionStart || connectEnd, "connect");
         if (secureConnectionStart)
             appendBlock(secureConnectionStart, connectEnd, "secure");
         appendBlock(requestStart, responseStart, "request");
@@ -1089,8 +1096,17 @@
 
     _checkURLFilterAgainstResource(resource)
     {
-        if (this._urlFilterSearchRegex.test(resource.url))
+        if (this._urlFilterSearchRegex.test(resource.url)) {
             this._activeURLFilterResources.add(resource);
+            return;
+        }
+
+        for (let redirect of resource.redirects) {
+            if (this._urlFilterSearchRegex.test(redirect.url)) {
+                this._activeURLFilterResources.add(resource);
+                return;
+            }
+        }
     }
 
     _rowIndexForResource(resource)
@@ -1689,7 +1705,7 @@
         let contentElement = document.createElement("div");
         contentElement.className = "waterfall-popover-content";
 
-        if (!resource.hasResponse() || !resource.timingData.startTime || !resource.timingData.responseEnd) {
+        if (!resource.hasResponse() || !resource.firstTimestamp || !resource.lastTimestamp) {
             contentElement.textContent = WI.UIString("Resource has no timing data");
             return contentElement;
         }

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.css (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.css	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.css	2018-10-10 02:49:52 UTC (rev 236995)
@@ -23,11 +23,11 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-body[dir] .resource-headers > section > .details {
+body[dir] .resource-headers > section.summary > .details {
     border-color: var(--network-system-color);
 }
 
-body[dir] .resource-headers > section.headers > .details {
+body[dir] .resource-headers > section:matches(.redirect, .headers) > .details {
     border-color: var(--network-header-color);
 }
 
@@ -55,7 +55,6 @@
 }
 
 .resource-headers .details .key {
-    color: var(--network-system-color);
     font-weight: 500;
     -webkit-margin-start: calc(var(--resource-headers-value-indent) * -1);
 }
@@ -64,6 +63,14 @@
     color: var(--text-color);
 }
 
+.resource-headers .url + .url > .key {
+    color: transparent;
+}
+
+.resource-headers .summary .key {
+    color: var(--network-system-color);
+}
+
 .resource-headers .header > .key {
     color: var(--network-header-color);
 }

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.js (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.js	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.js	2018-10-10 02:49:52 UTC (rev 236995)
@@ -46,10 +46,13 @@
         this._automaticallyRevealFirstSearchResult = false;
         this._bouncyHighlightElement = null;
 
+        this._redirectDetailsSections = [];
+
         this.element.classList.add("resource-details", "resource-headers");
         this.element.tabIndex = 0;
 
         this._needsSummaryRefresh = false;
+        this._needsRedirectHeadersRefresh = false;
         this._needsRequestHeadersRefresh = false;
         this._needsResponseHeadersRefresh = false;
     }
@@ -64,12 +67,12 @@
         this.element.appendChild(this._summarySection.element);
         this._refreshSummarySection();
 
+        this._refreshRedirectHeadersSections();
+
         this._requestHeadersSection = new WI.ResourceDetailsSection(WI.UIString("Request"), "headers");
         this.element.appendChild(this._requestHeadersSection.element);
         this._refreshRequestHeadersSection();
 
-        // FIXME: <https://webkit.org/b/150005> Web Inspector: Redirect requests are not shown in either Network or Timeline tabs
-
         this._responseHeadersSection = new WI.ResourceDetailsSection(WI.UIString("Response"), "headers");
         this.element.appendChild(this._responseHeadersSection.element);
         this._refreshResponseHeadersSection();
@@ -87,6 +90,7 @@
         }
 
         this._needsSummaryRefresh = false;
+        this._needsRedirectHeadersRefresh = false;
         this._needsRequestHeadersRefresh = false;
         this._needsResponseHeadersRefresh = false;
     }
@@ -100,6 +104,11 @@
             this._needsSummaryRefresh = false;
         }
 
+        if (this._needsRedirectHeadersRefresh) {
+            this._refreshRedirectHeadersSections();
+            this._needsRedirectHeadersRefresh = false;
+        }
+
         if (this._needsRequestHeadersRefresh) {
             this._refreshRequestHeadersSection();
             this._needsRequestHeadersRefresh = false;
@@ -266,7 +275,9 @@
 
         this._summarySection.toggleError(this._resource.hadLoadingError());
 
-        this._appendKeyValuePair(detailsElement, WI.UIString("URL"), this._resource.url.insertWordBreakCharacters());
+        for (let redirect of this._resource.redirects)
+            this._appendKeyValuePair(detailsElement, WI.UIString("URL"), redirect.url.insertWordBreakCharacters(), "url");
+        this._appendKeyValuePair(detailsElement, WI.UIString("URL"), this._resource.url.insertWordBreakCharacters(), "url");
 
         let status = emDash;
         if (!isNaN(this._resource.statusCode))
@@ -282,6 +293,37 @@
             this._appendKeyValuePair(detailsElement, WI.UIString("Address"), this._resource.remoteAddress);
     }
 
+    _refreshRedirectHeadersSections()
+    {
+        let referenceElement = this._redirectDetailsSections.length ? this._redirectDetailsSections.lastValue.element : this._summarySection.element;
+
+        for (let i = this._redirectDetailsSections.length; i < this._resource.redirects.length; ++i) {
+            let redirect = this._resource.redirects[i];
+
+            let redirectRequestSection = new WI.ResourceDetailsSection(WI.UIString("Request"), "redirect");
+
+            // FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
+            this._appendKeyValuePair(redirectRequestSection.detailsElement, `${redirect.requestMethod} ${redirect.urlComponents.path}`, null, "h1-status");
+
+            for (let key in redirect.requestHeaders)
+                this._appendKeyValuePair(redirectRequestSection.detailsElement, key, redirect.requestHeaders[key], "header");
+
+            referenceElement = this.element.insertBefore(redirectRequestSection.element, referenceElement.nextElementSibling);
+            this._redirectDetailsSections.push(redirectRequestSection);
+
+            let redirectResponseSection = new WI.ResourceDetailsSection(WI.UIString("Redirect Response"), "redirect");
+
+            // FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
+            this._appendKeyValuePair(redirectResponseSection.detailsElement, `${redirect.responseStatusCode} ${redirect.responseStatusText}`, null, "h1-status");
+
+            for (let key in redirect.responseHeaders)
+                this._appendKeyValuePair(redirectResponseSection.detailsElement, key, redirect.responseHeaders[key], "header");
+
+            referenceElement = this.element.insertBefore(redirectResponseSection.element, referenceElement.nextElementSibling);
+            this._redirectDetailsSections.push(redirectResponseSection);
+        }
+    }
+
     _refreshRequestHeadersSection()
     {
         let detailsElement = this._requestHeadersSection.detailsElement;
@@ -476,6 +518,8 @@
 
     _resourceRequestHeadersDidChange(event)
     {
+        this._needsSummaryRefresh = true;
+        this._needsRedirectHeadersRefresh = true;
         this._needsRequestHeadersRefresh = true;
         this.needsLayout();
     }

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js	2018-10-10 02:49:52 UTC (rev 236995)
@@ -396,9 +396,14 @@
                 }
             };
 
+            if (resource.timingData.redirectEnd - resource.timingData.redirectStart) {
+                // FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
+                popoverDataGrid.appendChild(new WI.ResourceTimingPopoverDataGridNode(WI.UIString("Redirects"), resource.timingData.redirectStart, resource.timingData.redirectEnd, graphDataSource));
+            }
+
             let secondTimestamp = resource.timingData.domainLookupStart || resource.timingData.connectStart || resource.timingData.requestStart;
-            if (secondTimestamp - resource.timingData.startTime)
-                popoverDataGrid.appendChild(new WI.ResourceTimingPopoverDataGridNode(WI.UIString("Stalled"), resource.timingData.startTime, secondTimestamp, graphDataSource));
+            if (secondTimestamp - resource.timingData.fetchStart)
+                popoverDataGrid.appendChild(new WI.ResourceTimingPopoverDataGridNode(WI.UIString("Stalled"), resource.timingData.fetchStart, secondTimestamp, graphDataSource));
             if (resource.timingData.domainLookupStart)
                 popoverDataGrid.appendChild(new WI.ResourceTimingPopoverDataGridNode(WI.UIString("DNS"), resource.timingData.domainLookupStart, resource.timingData.domainLookupEnd, graphDataSource));
             if (resource.timingData.connectStart)

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingBreakdownView.js (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingBreakdownView.js	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingBreakdownView.js	2018-10-10 02:49:52 UTC (rev 236995)
@@ -101,7 +101,7 @@
     {
         super.initialLayout();
 
-        let {startTime, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd} = this._resource.timingData;
+        let {startTime, redirectStart, redirectEnd, fetchStart, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd} = this._resource.timingData;
 
         this._tableElement = this.element.appendChild(document.createElement("table"));
         this._tableElement.className = "waterfall";
@@ -111,8 +111,14 @@
         this._graphDuration = this._graphEndTime - this._graphStartTime;
 
         this._appendHeaderRow(WI.UIString("Scheduling:"));
-        this._appendRow(WI.UIString("Queued"), "queue", startTime, domainLookupStart || connectStart || requestStart);
 
+        if (redirectEnd - redirectStart) {
+            // FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
+            this._appendRow(WI.UIString("Redirects"), "redirect", redirectStart, redirectEnd);
+        }
+
+        this._appendRow(WI.UIString("Queued"), "queue", fetchStart, domainLookupStart || connectStart || requestStart);
+
         if (domainLookupStart || connectStart) {
             this._appendEmptyRow();
             this._appendHeaderRow(WI.UIString("Connection:"));

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css (236994 => 236995)


--- trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css	2018-10-10 00:31:33 UTC (rev 236994)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css	2018-10-10 02:49:52 UTC (rev 236995)
@@ -113,6 +113,7 @@
     --network-pseudo-header-color: hsl(312, 35%, 51%);
     --network-error-color: hsl(0, 54%, 50%);
 
+    --network-redirect-color: lightgrey;
     --network-queue-color: hsl(0, 0%, 54%);
     --network-dns-color: hsl(265, 82%, 60%);
     --network-connect-color: hsl(46, 92%, 62%);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to