Bug 1441761 - Properly export total time; r=ochameau draft
authorJan Odvarko <odvarko@gmail.com>
Wed, 07 Mar 2018 13:19:38 +0100
changeset 764774 ed2b4b44662173cea9095ac4b6680b8cfe9dd601
parent 764770 a6a32fb286fa9e5d5f6d5b3b77423ab6b96c9502
push id101843
push userjodvarko@mozilla.com
push dateThu, 08 Mar 2018 09:02:07 +0000
reviewersochameau
bugs1441761
milestone60.0a1
Bug 1441761 - Properly export total time; r=ochameau MozReview-Commit-ID: EWt41uX4xDN
devtools/client/netmonitor/src/har/har-builder.js
devtools/client/netmonitor/src/har/har-collector.js
devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js
--- a/devtools/client/netmonitor/src/har/har-builder.js
+++ b/devtools/client/netmonitor/src/har/har-builder.js
@@ -10,16 +10,19 @@ const { LocalizationHelper } = require("
 const { CurlUtils } = require("devtools/client/shared/curl");
 const {
   getFormDataSections,
   getUrlQuery,
   parseQueryString,
 } = require("../utils/request-utils");
 const { buildHarLog } = require("./har-builder-utils");
 const L10N = new LocalizationHelper("devtools/client/locales/har.properties");
+const {
+  TIMING_KEYS
+} = require("../constants");
 
 /**
  * This object is responsible for building HAR file. See HAR spec:
  * https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HAR/Overview.html
  * http://www.softwareishard.com/blog/har-12-spec/
  *
  * @param {Object} options configuration object
  *
@@ -96,28 +99,40 @@ HarBuilder.prototype = {
   },
 
   buildEntry: async function (log, file) {
     let page = this.getPage(log, file);
 
     let entry = {};
     entry.pageref = page.id;
     entry.startedDateTime = dateToJSON(new Date(file.startedMillis));
-    entry.time = file.endedMillis - file.startedMillis;
 
     let eventTimings = file.eventTimings;
     if (!eventTimings && this._options.requestData) {
       eventTimings = await this._options.requestData(file.id, "eventTimings");
     }
 
     entry.request = await this.buildRequest(file);
     entry.response = await this.buildResponse(file);
     entry.cache = this.buildCache(file);
     entry.timings = eventTimings ? eventTimings.timings : {};
 
+    // Calculate total time by summing all timings. Note that
+    // `file.totalTime` can't be used since it doesn't have to
+    // correspond to plain summary of individual timings.
+    // With TCP Fast Open and TLS early data sending data can
+    // start at the same time as connect (we can send data on
+    // TCP syn packet). Also TLS handshake can carry application
+    // data thereby overlapping a sending data period and TLS
+    // handshake period.
+    entry.time = TIMING_KEYS.reduce((sum, type) => {
+      let time = entry.timings[type];
+      return (typeof time != "undefined") ? (sum + time) : sum;
+    }, 0);
+
     // Security state isn't part of HAR spec, and so create
     // custom field that needs to use '_' prefix.
     entry._securityState = file.securityState;
 
     if (file.remoteAddress) {
       entry.serverIPAddress = file.remoteAddress;
     }
 
--- a/devtools/client/netmonitor/src/har/har-collector.js
+++ b/devtools/client/netmonitor/src/har/har-collector.js
@@ -378,20 +378,17 @@ HarCollector.prototype = {
    * Handles additional information received for a "eventTimings" packet.
    *
    * @param object response
    *        The message received from the server.
    */
   onEventTimings: function (response) {
     let file = this.getFile(response.from);
     file.eventTimings = response;
-
-    let totalTime = response.totalTime;
-    file.totalTime = totalTime;
-    file.endedMillis = file.startedMillis + totalTime;
+    file.totalTime = response.totalTime;
   },
 
   // Helpers
 
   getLongHeaders: function (headers) {
     for (let header of headers) {
       if (typeof header.value == "object") {
         try {
--- a/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js
+++ b/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js
@@ -42,16 +42,17 @@ add_task(async function () {
   is(har.log.pages.length, 1, "There must be one page");
   is(har.log.entries.length, 1, "There must be one request");
 
   let page = har.log.pages[0];
   ok("onContentLoad" in page.pageTimings, "There must be onContentLoad time");
   ok("onLoad" in page.pageTimings, "There must be onLoad time");
 
   let entry = har.log.entries[0];
+  ok(entry.time > 0, "Check the total time");
   is(entry.request.method, "GET", "Check the method");
   is(entry.request.url, SIMPLE_URL, "Check the URL");
   is(entry.request.headers.length, 9, "Check number of request headers");
   is(entry.response.status, 200, "Check response status");
   is(entry.response.statusText, "OK", "Check response status text");
   is(entry.response.headers.length, 6, "Check number of response headers");
   is(entry.response.content.mimeType, // eslint-disable-line
     "text/html", "Check response content type"); // eslint-disable-line