⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 236995 in webkit


Ignore:
Timestamp:
Oct 9, 2018, 7:49:52 PM (8 years ago)
Author:
Devin Rousso
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/JavaScriptCore:

  • 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.
Location:
trunk
Files:
3 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r236991 r236995  
     12018-10-09  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: show redirect requests in Network and Timelines tabs
     4        https://bugs.webkit.org/show_bug.cgi?id=150005
     5        <rdar://problem/5378164>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        * http/tests/inspector/network/resource-timing-expected.txt:
     10        * http/tests/inspector/network/resource-timing.html:
     11
     12        * http/tests/inspector/network/resources/delay.php: Added.
     13        * http/tests/inspector/network/resources/redirect.php: Added.
     14
    1152018-10-09  Said Abou-Hallawa  <sabouhallawa@apple.com>
    216
  • trunk/LayoutTests/http/tests/inspector/network/resource-timing-expected.txt

    r213621 r236995  
    22
    33
    4 == Running test suite: ResourceTimingData
    5 -- Running test case: CheckResourceTimingInformationForResource
     4== Running test suite: Resource.TimingData
     5-- Running test case: Resource.TimingData.Basic
    66PASS: Resource should be created.
    77PASS: Added Resource received a response.
     
    99PASS: Newly added resource should have a resource timing model.
    1010PASS: Resource should have a start time.
     11PASS: Resource should have a fetch start time.
    1112PASS: Resource should have a request start time.
    1213PASS: Resource should have a response start time.
     
    1819PASS: responseEnd should come after responseStart.
    1920
     21-- Running test case: Resource.TimingData.Redirect
     22PASS: Start time should be before redirect start time.
     23PASS: Redirect start time should be before redirect end time.
     24PASS: Redirect duration should be at least a few milliseconds.
     25PASS: Redirect end time should be before fetch start time.
     26
  • trunk/LayoutTests/http/tests/inspector/network/resource-timing.html

    r220119 r236995  
    55<script src="../resources/inspector-test.js"></script>
    66<script>
    7 function createRequest() {
     7function createImageRequest() {
    88    let img = document.createElement("img");
    99    img.src = "https://localhost:8443/resources/square100.png";
     
    1111}
    1212
     13function createRedirectRequest(delay) {
     14    let iframe = document.createElement("iframe");
     15    iframe.src = `resources/delay.php?delay=${delay}`;
     16    document.body.appendChild(iframe);
     17}
     18
    1319function test()
    1420{
    15     let suite = InspectorTest.createAsyncSuite("ResourceTimingData");
     21    let suite = InspectorTest.createAsyncSuite("Resource.TimingData");
    1622
    1723    suite.addTestCase({
    18         name: "CheckResourceTimingInformationForResource",
     24        name: "Resource.TimingData.Basic",
    1925        description: "Check if a resource has timing information.",
    2026        test(resolve, reject) {
     
    3339                let timingData = resource.timingData;
    3440                InspectorTest.expectThat(timingData instanceof WI.ResourceTimingData, "Newly added resource should have a resource timing model.");
    35                 InspectorTest.expectThat(timingData.startTime > 0, "Resource should have a start time.");
    36                 InspectorTest.expectThat(timingData.requestStart > 0, "Resource should have a request start time.");
    37                 InspectorTest.expectThat(timingData.responseStart > 0, "Resource should have a response start time.");
     41                InspectorTest.expectGreaterThan(timingData.startTime, 0, "Resource should have a start time.");
     42                InspectorTest.expectGreaterThan(timingData.fetchStart, 0, "Resource should have a fetch start time.");
     43                InspectorTest.expectGreaterThan(timingData.requestStart, 0, "Resource should have a request start time.");
     44                InspectorTest.expectGreaterThan(timingData.responseStart, 0, "Resource should have a response start time.");
    3845
    3946                InspectorTest.expectThat(typeof timingData.domainLookupStart === "number" && typeof timingData.domainLookupEnd === "number", "domainLookupStart and domainLookupEnd should both be NaN or a number.");
    4047                InspectorTest.expectThat(typeof timingData.connectStart === "number" && typeof timingData.connectStart === "number", "connectStart and connectEnd should both be NaN or a number.");
    4148
    42                 InspectorTest.expectThat(timingData.startTime <= timingData.requestStart, "requestStart should come after startTime.");
     49                InspectorTest.expectLessThanOrEqual(timingData.startTime, timingData.requestStart, "requestStart should come after startTime.");
    4350                InspectorTest.expectThat(isNaN(timingData.secureConnectionStart) || timingData.connectStart <= timingData.secureConnectionStart, "A secure connection should be reused or secureConnectionStart should come after connectStart.");
    44                 InspectorTest.expectThat(timingData.requestStart <= timingData.responseStart, "responseStart should come after requestStart.");
    45                 InspectorTest.expectThat(timingData.responseStart <= timingData.responseEnd, "responseEnd should come after responseStart.");
     51                InspectorTest.expectLessThanOrEqual(timingData.requestStart, timingData.responseStart, "responseStart should come after requestStart.");
     52                InspectorTest.expectLessThanOrEqual(timingData.responseStart, timingData.responseEnd, "responseEnd should come after responseStart.");
    4653            })
    4754            .then(resolve, reject);
    4855
    49             InspectorTest.evaluateInPage("createRequest()");
     56            InspectorTest.evaluateInPage(`createImageRequest()`);
     57        }
     58    });
     59
     60    suite.addTestCase({
     61        name: "Resource.TimingData.Redirect",
     62        description: "Check if a redirected resource has timing information.",
     63        test(resolve, reject) {
     64            const delay = 100;
     65
     66            WI.Resource.awaitEvent(WI.Resource.Event.ResponseReceived)
     67            .then((event) => {
     68                let resource = event.target;
     69
     70                let timingData = resource.timingData;
     71                InspectorTest.assert(timingData.startTime >= 0, "Resource should have a start time.");
     72                InspectorTest.assert(timingData.redirectStart >= 0, "Resource should have a redirect start time.");
     73                InspectorTest.assert(timingData.redirectEnd >= 0, "Resource should have a redirect end time.");
     74                InspectorTest.assert(timingData.fetchStart >= 0, "Resource should have a fetch start time.");
     75
     76                InspectorTest.expectLessThanOrEqual(timingData.startTime, timingData.redirectStart, "Start time should be before redirect start time.");
     77                InspectorTest.expectLessThan(timingData.redirectStart, timingData.redirectEnd, "Redirect start time should be before redirect end time.");
     78                InspectorTest.expectGreaterThanOrEqual(timingData.redirectEnd - timingData.redirectStart, (delay / 2) / 1000, "Redirect duration should be at least a few milliseconds.");
     79                InspectorTest.expectLessThanOrEqual(timingData.redirectEnd, timingData.fetchStart, "Redirect end time should be before fetch start time.");
     80            })
     81            .then(resolve, reject);
     82
     83            InspectorTest.evaluateInPage(`createRedirectRequest(${delay})`);
    5084        }
    5185    });
  • trunk/Source/JavaScriptCore/ChangeLog

    r236975 r236995  
     12018-10-09  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: show redirect requests in Network and Timelines tabs
     4        https://bugs.webkit.org/show_bug.cgi?id=150005
     5        <rdar://problem/5378164>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        * inspector/protocol/Network.json:
     10        Add missing fields to `ResourceTiming`.
     11
    1122018-10-09  Claudio Saavedra  <csaavedra@igalia.com>
    213
  • trunk/Source/JavaScriptCore/inspector/protocol/Network.json

    r236927 r236995  
    3939            "description": "Timing information for the request.",
    4040            "properties": [
    41                 { "name": "startTime", "type": "number", "description": "Timing's startTime is a baseline in seconds, while the other numbers are ticks in milliseconds relatively to this." },
    42                 { "name": "domainLookupStart", "type": "number", "description": "Started DNS address resolve." },
    43                 { "name": "domainLookupEnd", "type": "number", "description": "Finished DNS address resolve." },
    44                 { "name": "connectStart", "type": "number", "description": "Started connecting to the remote host." },
    45                 { "name": "connectEnd", "type": "number", "description": "Connected to the remote host." },
    46                 { "name": "secureConnectionStart", "type": "number", "description": "Started SSL handshake." },
    47                 { "name": "requestStart", "type": "number", "description": "Started sending request." },
    48                 { "name": "responseStart", "type": "number", "description": "Started receiving response headers." }
     41                { "name": "startTime", "$ref": "Timestamp", "description": "Request is initiated" },
     42                { "name": "redirectStart", "$ref": "Timestamp", "description": "Started redirect resolution." },
     43                { "name": "redirectEnd", "$ref": "Timestamp", "description": "Finished redirect resolution." },
     44                { "name": "fetchStart", "$ref": "Timestamp", "description": "Resource fetching started." },
     45                { "name": "domainLookupStart", "type": "number", "description": "Started DNS address resolve in milliseconds relative to fetchStart." },
     46                { "name": "domainLookupEnd", "type": "number", "description": "Finished DNS address resolve in milliseconds relative to fetchStart." },
     47                { "name": "connectStart", "type": "number", "description": "Started connecting to the remote host in milliseconds relative to fetchStart." },
     48                { "name": "connectEnd", "type": "number", "description": "Connected to the remote host in milliseconds relative to fetchStart." },
     49                { "name": "secureConnectionStart", "type": "number", "description": "Started SSL handshake in milliseconds relative to fetchStart." },
     50                { "name": "requestStart", "type": "number", "description": "Started sending request in milliseconds relative to fetchStart." },
     51                { "name": "responseStart", "type": "number", "description": "Started receiving response headers in milliseconds relative to fetchStart." },
     52                { "name": "responseEnd", "type": "number", "description": "Finished receiving response headers in milliseconds relative to fetchStart." }
    4953            ]
    5054        },
  • trunk/Source/WebCore/ChangeLog

    r236991 r236995  
     12018-10-09  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: show redirect requests in Network and Timelines tabs
     4        https://bugs.webkit.org/show_bug.cgi?id=150005
     5        <rdar://problem/5378164>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        Updated existing test http/tests/inspector/network/resource-timing.html.
     10
     11        * inspector/agents/InspectorNetworkAgent.cpp:
     12        (WebCore::InspectorNetworkAgent::buildObjectForTiming):
     13        (WebCore::InspectorNetworkAgent::didFinishLoading):
     14        Add missing fields for `Network.types.ResourceTiming`.
     15
    1162018-10-09  Said Abou-Hallawa  <sabouhallawa@apple.com>
    217
  • trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp

    r236927 r236995  
    198198Ref<Inspector::Protocol::Network::ResourceTiming> InspectorNetworkAgent::buildObjectForTiming(const NetworkLoadMetrics& timing, ResourceLoader& resourceLoader)
    199199{
    200     MonotonicTime startTime = resourceLoader.loadTiming().startTime();
    201     Seconds startTimeInInspector = m_environment.executionStopwatch()->elapsedTimeSince(startTime);
     200    auto& loadTiming = resourceLoader.loadTiming();
     201
     202    auto elapsedTimeSince = [&] (const MonotonicTime& time) {
     203        return m_environment.executionStopwatch()->elapsedTimeSince(time).seconds();
     204    };
    202205
    203206    return Inspector::Protocol::Network::ResourceTiming::create()
    204         .setStartTime(startTimeInInspector.seconds())
     207        .setStartTime(elapsedTimeSince(loadTiming.startTime()))
     208        .setRedirectStart(elapsedTimeSince(loadTiming.redirectStart()))
     209        .setRedirectEnd(elapsedTimeSince(loadTiming.redirectEnd()))
     210        .setFetchStart(elapsedTimeSince(loadTiming.fetchStart()))
    205211        .setDomainLookupStart(timing.domainLookupStart.milliseconds())
    206212        .setDomainLookupEnd(timing.domainLookupEnd.milliseconds())
     
    210216        .setRequestStart(timing.requestStart.milliseconds())
    211217        .setResponseStart(timing.responseStart.milliseconds())
     218        .setResponseEnd(timing.responseEnd.milliseconds())
    212219        .release();
    213220}
     
    507514    double elapsedFinishTime;
    508515    if (resourceLoader && networkLoadMetrics.isComplete()) {
    509         MonotonicTime startTime = resourceLoader->loadTiming().startTime();
    510         Seconds startTimeInInspector = m_environment.executionStopwatch()->elapsedTimeSince(startTime);
    511         elapsedFinishTime = (startTimeInInspector + networkLoadMetrics.responseEnd).seconds();
     516        MonotonicTime fetchStart = resourceLoader->loadTiming().fetchStart();
     517        Seconds fetchStartInInspector = m_environment.executionStopwatch()->elapsedTimeSince(fetchStart);
     518        elapsedFinishTime = (fetchStartInInspector + networkLoadMetrics.responseEnd).seconds();
    512519    } else
    513520        elapsedFinishTime = timestamp();
  • trunk/Source/WebInspectorUI/ChangeLog

    r236986 r236995  
     12018-10-09  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: show redirect requests in Network and Timelines tabs
     4        https://bugs.webkit.org/show_bug.cgi?id=150005
     5        <rdar://problem/5378164>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        * Localizations/en.lproj/localizedStrings.js:
     10        * UserInterface/Views/Variables.css:
     11        * UserInterface/Main.html:
     12        * UserInterface/Test.html:
     13
     14        * UserInterface/Controllers/NetworkManager.js:
     15        (WI.NetworkManager.prototype.resourceRequestWillBeSent):
     16
     17        * UserInterface/Models/Resource.js:
     18        (WI.Resource):
     19        (WI.Resource.prototype.get redirects): Added.
     20        (WI.Resource.prototype.get lastRedirectReceivedTimestamp):
     21        (WI.Resource.prototype.updateForRedirectResponse):
     22        Save each redirect in an array instead of just remembering the last timestamp.
     23
     24        * UserInterface/Models/ResourceTimingData.js:
     25        (WI.ResourceTimingData):
     26        (WI.ResourceTimingData.fromPayload.offsetToTimestamp):
     27        (WI.ResourceTimingData.fromPayload):
     28        (WI.ResourceTimingData.prototype.get redirectStart): Added.
     29        (WI.ResourceTimingData.prototype.get redirectEnd): Added.
     30        (WI.ResourceTimingData.prototype.get fetchStart): Added.
     31        Add missing fields for `Network.types.ResourceTiming`.
     32
     33        * UserInterface/Models/Redirect.js: Added.
     34        (WI.Redirect):
     35        (WI.Redirect.prototype.get url):
     36        (WI.Redirect.prototype.get requestMethod):
     37        (WI.Redirect.prototype.get requestHeaders):
     38        (WI.Redirect.prototype.get responseStatusCode):
     39        (WI.Redirect.prototype.get responseStatusText):
     40        (WI.Redirect.prototype.get responseHeaders):
     41        (WI.Redirect.prototype.get timestamp):
     42        (WI.Redirect.prototype.get urlComponents):
     43
     44        * UserInterface/Views/ResourceHeadersContentView.js:
     45        (WI.ResourceHeadersContentView):
     46        (WI.ResourceHeadersContentView.prototype.initialLayout):
     47        (WI.ResourceHeadersContentView.prototype.layout):
     48        (WI.ResourceHeadersContentView.prototype._refreshRedirectHeadersSections): Added.
     49        (WI.ResourceHeadersContentView.prototype._resourceRequestHeadersDidChange):
     50        * UserInterface/Views/ResourceHeadersContentView.css:
     51        (body[dir] .resource-headers > section.summary > .details): Added.
     52        (body[dir] .resource-headers > section:matches(.redirect, .headers) > .details): Added.
     53        (.resource-headers .details .key):
     54        (.resource-headers .summary .key):
     55        (body[dir] .resource-headers > section > .details): Deleted.
     56        (body[dir] .resource-headers > section.headers > .details): Deleted.
     57        (.resource-headers .value): Deleted.
     58        Add a request/response header section for each redirect.
     59
     60        * UserInterface/Views/NetworkTableContentView.js:
     61        (WI.NetworkTableContentView.prototype._populateWaterfallGraph.appendBlock):
     62        (WI.NetworkTableContentView.prototype._populateWaterfallGraph):
     63        (WI.NetworkTableContentView.prototype._checkURLFilterAgainstResource):
     64        (WI.NetworkTableContentView.prototype._waterfallPopoverContentForResource):
     65        * UserInterface/Views/NetworkTableContentView.css:
     66        (.waterfall .block.redirect): Added.
     67        (.waterfall .block.queue):
     68        * UserInterface/Views/ResourceTimelineDataGridNode.js:
     69        (WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar):
     70        * UserInterface/Views/ResourceTimingBreakdownView.js:
     71        (WI.ResourceTimingBreakdownView.prototype.initialLayout):
     72        Add timeline/waterfall entries for total redirect time.
     73
    1742018-10-09  Devin Rousso  <drousso@apple.com>
    275
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r236927 r236995  
    655655localizedStrings["Recording error: %s"] = "Recording error: %s";
    656656localizedStrings["Recordings"] = "Recordings";
     657localizedStrings["Redirect Response"] = "Redirect Response";
     658localizedStrings["Redirects"] = "Redirects";
    657659localizedStrings["Reference Issue"] = "Reference Issue";
    658660localizedStrings["Reflection"] = "Reflection";
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/NetworkManager.js

    r236927 r236995  
    240240        if (resource) {
    241241            // This is an existing request which is being redirected, update the resource.
    242             console.assert(redirectResponse);
     242            console.assert(resource.parentFrame.id === frameIdentifier);
     243            console.assert(resource.loaderIdentifier === loaderIdentifier);
    243244            console.assert(!targetId);
    244             resource.updateForRedirectResponse(request.url, request.headers, elapsedTime);
     245            resource.updateForRedirectResponse(request, redirectResponse, elapsedTime, walltime);
    245246            return;
    246247        }
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r236853 r236995  
    405405    <script src="Models/RecordingFrame.js"></script>
    406406    <script src="Models/RecordingInitialStateAction.js"></script>
     407    <script src="Models/Redirect.js"></script>
    407408    <script src="Models/RenderingFrameTimelineRecord.js"></script>
    408409    <script src="Models/ResourceCollection.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js

    r236950 r236995  
    5959        this._requestSentWalltime = requestSentWalltime || NaN;
    6060        this._responseReceivedTimestamp = NaN;
    61         this._lastRedirectReceivedTimestamp = NaN;
    6261        this._lastDataReceivedTimestamp = NaN;
    6362        this._finishedOrFailedTimestamp = NaN;
     
    7776        this._connectionIdentifier = null;
    7877        this._target = targetId ? WI.targetManager.targetForIdentifier(targetId) : WI.mainTarget;
     78        this._redirects = [];
    7979
    8080        // Exact sizes if loaded over the network or cache.
     
    320320    get requestSentTimestamp() { return this._requestSentTimestamp; }
    321321    get requestSentWalltime() { return this._requestSentWalltime; }
    322     get lastRedirectReceivedTimestamp() { return this._lastRedirectReceivedTimestamp; }
    323322    get responseReceivedTimestamp() { return this._responseReceivedTimestamp; }
    324323    get lastDataReceivedTimestamp() { return this._lastDataReceivedTimestamp; }
     
    330329    get responseBodyTransferSize() { return this._responseBodyTransferSize; }
    331330    get cachedResponseBodySize() { return this._cachedResponseBodySize; }
     331    get redirects() { return this._redirects; }
    332332
    333333    get urlComponents()
     
    468468    }
    469469
     470    get lastRedirectReceivedTimestamp()
     471    {
     472        return this._redirects.length ? this._redirects.lastValue.timestamp : NaN;
     473    }
     474
    470475    get firstTimestamp()
    471476    {
     
    625630    }
    626631
    627     updateForRedirectResponse(url, requestHeaders, elapsedTime)
     632    updateForRedirectResponse(request, response, elapsedTime, walltime)
    628633    {
    629634        console.assert(!this._finished);
     
    631636        console.assert(!this._canceled);
    632637
    633         var oldURL = this._url;
    634 
    635         if (url)
    636             this._url = url;
    637 
    638         this._requestHeaders = requestHeaders || {};
     638        let oldURL = this._url;
     639        let oldHeaders = this._requestHeaders;
     640
     641        if (request.url)
     642            this._url = request.url;
     643
     644        this._requestHeaders = request.headers || {};
    639645        this._requestCookies = null;
    640         this._lastRedirectReceivedTimestamp = elapsedTime || NaN;
    641 
    642         if (oldURL !== url) {
     646        this._redirects.push(new WI.Redirect(oldURL, request.method, oldHeaders, response.status, response.statusText, response.headers, elapsedTime));
     647
     648        if (oldURL !== request.url) {
    643649            // Delete the URL components so the URL is re-parsed the next time it is requested.
    644650            this._urlComponents = null;
  • trunk/Source/WebInspectorUI/UserInterface/Models/ResourceTimingData.js

    r226914 r236995  
    3030        data = data || {};
    3131
     32        console.assert(isNaN(data.startTime) || data.startTime <= data.fetchStart);
     33        console.assert(isNaN(data.redirectStart) === isNaN(data.redirectEnd));
    3234        console.assert(isNaN(data.domainLookupStart) === isNaN(data.domainLookupEnd));
    3335        console.assert(isNaN(data.connectStart) === isNaN(data.connectEnd));
     
    3638
    3739        this._startTime = data.startTime || NaN;
     40        this._redirectStart = data.redirectStart || NaN;
     41        this._redirectEnd = data.redirectEnd || NaN;
     42        this._fetchStart = data.fetchStart || NaN;
    3843        this._domainLookupStart = data.domainLookupStart || NaN;
    3944        this._domainLookupEnd = data.domainLookupEnd || NaN;
     
    6368            payload = {};
    6469
     70        // COMPATIBILITY (iOS 12.0): Resource Timing data was based on startTime, not fetchStart.
     71        let startTime = payload.startTime;
     72        let fetchStart = payload.fetchStart;
     73        let redirectStart = payload.redirectStart;
     74        let redirectEnd = payload.redirectEnd;
     75
     76        if (isNaN(fetchStart) || fetchStart < startTime)
     77            fetchStart = startTime;
     78
     79        if (redirectStart < startTime || redirectStart > fetchStart || redirectStart > redirectEnd)
     80            redirectStart = NaN;
     81
     82        if (redirectEnd < startTime || redirectEnd > fetchStart || redirectEnd < redirectStart)
     83            redirectEnd = NaN;
     84
    6585        function offsetToTimestamp(offset) {
    66             return offset > 0 ? payload.startTime + (offset / 1000) : NaN;
     86            return offset > 0 ? fetchStart + (offset / 1000) : NaN;
    6787        }
    6888
    6989        let data = {
    70             startTime: payload.startTime,
     90            startTime,
     91            redirectStart,
     92            redirectEnd,
     93            fetchStart,
    7194            domainLookupStart: offsetToTimestamp(payload.domainLookupStart),
    7295            domainLookupEnd: offsetToTimestamp(payload.domainLookupEnd),
     
    89112
    90113    get startTime() { return this._startTime || this._resource.requestSentTimestamp; }
     114    get redirectStart() { return this._redirectStart; }
     115    get redirectEnd() { return this._redirectEnd; }
     116    get fetchStart() { return this._fetchStart; }
    91117    get domainLookupStart() { return this._domainLookupStart; }
    92118    get domainLookupEnd() { return this._domainLookupEnd; }
  • trunk/Source/WebInspectorUI/UserInterface/Test.html

    r236853 r236995  
    174174    <script src="Models/RecordingFrame.js"></script>
    175175    <script src="Models/RecordingInitialStateAction.js"></script>
     176    <script src="Models/Redirect.js"></script>
    176177    <script src="Models/RenderingFrameTimelineRecord.js"></script>
    177178    <script src="Models/ResourceCollection.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css

    r236927 r236995  
    187187}
    188188
     189.waterfall .block.filler {
     190    top: 9px;
     191    height: 2px;
     192    background-color: lightgrey;
     193}
     194
     195.waterfall .block.redirect {
     196    background-color: var(--network-redirect-color);
     197}
     198
    189199.waterfall .block.queue {
    190     min-width: 3px;
    191     -webkit-margin-start: -1px;
    192200    background-color: var(--network-queue-color);
    193201}
  • trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js

    r236950 r236995  
    652652        }
    653653
    654         let {startTime, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd} = resource.timingData;
    655         if (isNaN(startTime)) {
     654        let {startTime, redirectStart, redirectEnd, fetchStart, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd} = resource.timingData;
     655        if (isNaN(startTime) || isNaN(responseEnd)) {
    656656            cell.textContent = zeroWidthSpace;
    657657            return;
     
    675675        container.className = "waterfall-container";
    676676
    677         function appendBlock(startTime, endTime, className) {
    678             let startOffset = (startTime - graphStartTime) / secondsPerPixel;
    679             let width = (endTime - startTime) / secondsPerPixel;
     677        function appendBlock(startTimestamp, endTimestamp, className) {
     678            if (isNaN(startTimestamp) || isNaN(endTimestamp) || endTimestamp - startTimestamp <= 0)
     679                return null;
     680
     681            let startOffset = (startTimestamp - graphStartTime) / secondsPerPixel;
     682            let width = (endTimestamp - startTimestamp) / secondsPerPixel;
    680683            let block = container.appendChild(document.createElement("div"));
    681684            block.classList.add("block", className);
     
    703706        }
    704707
    705         // Each component.
     708        appendBlock(startTime, responseEnd, "filler");
     709
     710        // FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
     711        appendBlock(redirectStart, redirectEnd, "redirect");
     712
    706713        if (domainLookupStart) {
    707             appendBlock(startTime, domainLookupStart, "queue");
    708             appendBlock(domainLookupStart, connectStart || requestStart, "dns");
     714            appendBlock(fetchStart, domainLookupStart, "queue");
     715            appendBlock(domainLookupStart, domainLookupEnd || connectStart || requestStart, "dns");
    709716        } else if (connectStart)
    710             appendBlock(startTime, connectStart, "queue");
     717            appendBlock(fetchStart, connectStart, "queue");
    711718        else if (requestStart)
    712             appendBlock(startTime, requestStart, "queue");
     719            appendBlock(fetchStart, requestStart, "queue");
    713720        if (connectStart)
    714             appendBlock(connectStart, connectEnd, "connect");
     721            appendBlock(connectStart, secureConnectionStart || connectEnd, "connect");
    715722        if (secureConnectionStart)
    716723            appendBlock(secureConnectionStart, connectEnd, "secure");
     
    10901097    _checkURLFilterAgainstResource(resource)
    10911098    {
    1092         if (this._urlFilterSearchRegex.test(resource.url))
     1099        if (this._urlFilterSearchRegex.test(resource.url)) {
    10931100            this._activeURLFilterResources.add(resource);
     1101            return;
     1102        }
     1103
     1104        for (let redirect of resource.redirects) {
     1105            if (this._urlFilterSearchRegex.test(redirect.url)) {
     1106                this._activeURLFilterResources.add(resource);
     1107                return;
     1108            }
     1109        }
    10941110    }
    10951111
     
    16901706        contentElement.className = "waterfall-popover-content";
    16911707
    1692         if (!resource.hasResponse() || !resource.timingData.startTime || !resource.timingData.responseEnd) {
     1708        if (!resource.hasResponse() || !resource.firstTimestamp || !resource.lastTimestamp) {
    16931709            contentElement.textContent = WI.UIString("Resource has no timing data");
    16941710            return contentElement;
  • trunk/Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.css

    r236705 r236995  
    2424 */
    2525
    26 body[dir] .resource-headers > section > .details {
     26body[dir] .resource-headers > section.summary > .details {
    2727    border-color: var(--network-system-color);
    2828}
    2929
    30 body[dir] .resource-headers > section.headers > .details {
     30body[dir] .resource-headers > section:matches(.redirect, .headers) > .details {
    3131    border-color: var(--network-header-color);
    3232}
     
    5656
    5757.resource-headers .details .key {
    58     color: var(--network-system-color);
    5958    font-weight: 500;
    6059    -webkit-margin-start: calc(var(--resource-headers-value-indent) * -1);
     
    6362.resource-headers .value {
    6463    color: var(--text-color);
     64}
     65
     66.resource-headers .url + .url > .key {
     67    color: transparent;
     68}
     69
     70.resource-headers .summary .key {
     71    color: var(--network-system-color);
    6572}
    6673
  • trunk/Source/WebInspectorUI/UserInterface/Views/ResourceHeadersContentView.js

    r226821 r236995  
    4747        this._bouncyHighlightElement = null;
    4848
     49        this._redirectDetailsSections = [];
     50
    4951        this.element.classList.add("resource-details", "resource-headers");
    5052        this.element.tabIndex = 0;
    5153
    5254        this._needsSummaryRefresh = false;
     55        this._needsRedirectHeadersRefresh = false;
    5356        this._needsRequestHeadersRefresh = false;
    5457        this._needsResponseHeadersRefresh = false;
     
    6568        this._refreshSummarySection();
    6669
     70        this._refreshRedirectHeadersSections();
     71
    6772        this._requestHeadersSection = new WI.ResourceDetailsSection(WI.UIString("Request"), "headers");
    6873        this.element.appendChild(this._requestHeadersSection.element);
    6974        this._refreshRequestHeadersSection();
    70 
    71         // FIXME: <https://webkit.org/b/150005> Web Inspector: Redirect requests are not shown in either Network or Timeline tabs
    7275
    7376        this._responseHeadersSection = new WI.ResourceDetailsSection(WI.UIString("Response"), "headers");
     
    8891
    8992        this._needsSummaryRefresh = false;
     93        this._needsRedirectHeadersRefresh = false;
    9094        this._needsRequestHeadersRefresh = false;
    9195        this._needsResponseHeadersRefresh = false;
     
    99103            this._refreshSummarySection();
    100104            this._needsSummaryRefresh = false;
     105        }
     106
     107        if (this._needsRedirectHeadersRefresh) {
     108            this._refreshRedirectHeadersSections();
     109            this._needsRedirectHeadersRefresh = false;
    101110        }
    102111
     
    267276        this._summarySection.toggleError(this._resource.hadLoadingError());
    268277
    269         this._appendKeyValuePair(detailsElement, WI.UIString("URL"), this._resource.url.insertWordBreakCharacters());
     278        for (let redirect of this._resource.redirects)
     279            this._appendKeyValuePair(detailsElement, WI.UIString("URL"), redirect.url.insertWordBreakCharacters(), "url");
     280        this._appendKeyValuePair(detailsElement, WI.UIString("URL"), this._resource.url.insertWordBreakCharacters(), "url");
    270281
    271282        let status = emDash;
     
    281292        if (this._resource.remoteAddress)
    282293            this._appendKeyValuePair(detailsElement, WI.UIString("Address"), this._resource.remoteAddress);
     294    }
     295
     296    _refreshRedirectHeadersSections()
     297    {
     298        let referenceElement = this._redirectDetailsSections.length ? this._redirectDetailsSections.lastValue.element : this._summarySection.element;
     299
     300        for (let i = this._redirectDetailsSections.length; i < this._resource.redirects.length; ++i) {
     301            let redirect = this._resource.redirects[i];
     302
     303            let redirectRequestSection = new WI.ResourceDetailsSection(WI.UIString("Request"), "redirect");
     304
     305            // FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
     306            this._appendKeyValuePair(redirectRequestSection.detailsElement, `${redirect.requestMethod} ${redirect.urlComponents.path}`, null, "h1-status");
     307
     308            for (let key in redirect.requestHeaders)
     309                this._appendKeyValuePair(redirectRequestSection.detailsElement, key, redirect.requestHeaders[key], "header");
     310
     311            referenceElement = this.element.insertBefore(redirectRequestSection.element, referenceElement.nextElementSibling);
     312            this._redirectDetailsSections.push(redirectRequestSection);
     313
     314            let redirectResponseSection = new WI.ResourceDetailsSection(WI.UIString("Redirect Response"), "redirect");
     315
     316            // FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
     317            this._appendKeyValuePair(redirectResponseSection.detailsElement, `${redirect.responseStatusCode} ${redirect.responseStatusText}`, null, "h1-status");
     318
     319            for (let key in redirect.responseHeaders)
     320                this._appendKeyValuePair(redirectResponseSection.detailsElement, key, redirect.responseHeaders[key], "header");
     321
     322            referenceElement = this.element.insertBefore(redirectResponseSection.element, referenceElement.nextElementSibling);
     323            this._redirectDetailsSections.push(redirectResponseSection);
     324        }
    283325    }
    284326
     
    477519    _resourceRequestHeadersDidChange(event)
    478520    {
     521        this._needsSummaryRefresh = true;
     522        this._needsRedirectHeadersRefresh = true;
    479523        this._needsRequestHeadersRefresh = true;
    480524        this.needsLayout();
  • trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js

    r226151 r236995  
    397397            };
    398398
     399            if (resource.timingData.redirectEnd - resource.timingData.redirectStart) {
     400                // FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
     401                popoverDataGrid.appendChild(new WI.ResourceTimingPopoverDataGridNode(WI.UIString("Redirects"), resource.timingData.redirectStart, resource.timingData.redirectEnd, graphDataSource));
     402            }
     403
    399404            let secondTimestamp = resource.timingData.domainLookupStart || resource.timingData.connectStart || resource.timingData.requestStart;
    400             if (secondTimestamp - resource.timingData.startTime)
    401                 popoverDataGrid.appendChild(new WI.ResourceTimingPopoverDataGridNode(WI.UIString("Stalled"), resource.timingData.startTime, secondTimestamp, graphDataSource));
     405            if (secondTimestamp - resource.timingData.fetchStart)
     406                popoverDataGrid.appendChild(new WI.ResourceTimingPopoverDataGridNode(WI.UIString("Stalled"), resource.timingData.fetchStart, secondTimestamp, graphDataSource));
    402407            if (resource.timingData.domainLookupStart)
    403408                popoverDataGrid.appendChild(new WI.ResourceTimingPopoverDataGridNode(WI.UIString("DNS"), resource.timingData.domainLookupStart, resource.timingData.domainLookupEnd, graphDataSource));
  • trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingBreakdownView.js

    r226158 r236995  
    102102        super.initialLayout();
    103103
    104         let {startTime, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd} = this._resource.timingData;
     104        let {startTime, redirectStart, redirectEnd, fetchStart, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, responseStart, responseEnd} = this._resource.timingData;
    105105
    106106        this._tableElement = this.element.appendChild(document.createElement("table"));
     
    112112
    113113        this._appendHeaderRow(WI.UIString("Scheduling:"));
    114         this._appendRow(WI.UIString("Queued"), "queue", startTime, domainLookupStart || connectStart || requestStart);
     114
     115        if (redirectEnd - redirectStart) {
     116            // FIXME: <https://webkit.org/b/190214> Web Inspector: expose full load metrics for redirect requests
     117            this._appendRow(WI.UIString("Redirects"), "redirect", redirectStart, redirectEnd);
     118        }
     119
     120        this._appendRow(WI.UIString("Queued"), "queue", fetchStart, domainLookupStart || connectStart || requestStart);
    115121
    116122        if (domainLookupStart || connectStart) {
  • trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css

    r236705 r236995  
    114114    --network-error-color: hsl(0, 54%, 50%);
    115115
     116    --network-redirect-color: lightgrey;
    116117    --network-queue-color: hsl(0, 0%, 54%);
    117118    --network-dns-color: hsl(265, 82%, 60%);
Note: See TracChangeset for help on using the changeset viewer.