Bug 1434855 - Improve performance of HAR export; r=ochameau draft
authorJan Odvarko <odvarko@gmail.com>
Thu, 08 Mar 2018 12:45:36 +0100
changeset 764821 ab9e8e9ea68ae91e8fe4f28c344c41e2324e223f
parent 764820 4b88ddf3b5c14b0d9f1cb8f71018cd556ebbe353
push id101860
push userjodvarko@mozilla.com
push dateThu, 08 Mar 2018 11:46:38 +0000
reviewersochameau
bugs1434855
milestone60.0a1
Bug 1434855 - Improve performance of HAR export; r=ochameau MozReview-Commit-ID: 6H6P6wYmdQL
browser/components/extensions/test/browser/browser_ext_devtools_network.js
devtools/client/netmonitor/src/connector/chrome-connector.js
devtools/client/netmonitor/src/connector/firefox-connector.js
devtools/client/netmonitor/src/connector/firefox-data-provider.js
devtools/client/netmonitor/src/connector/index.js
devtools/client/netmonitor/src/har/har-exporter.js
--- a/browser/components/extensions/test/browser/browser_ext_devtools_network.js
+++ b/browser/components/extensions/test/browser/browser_ext_devtools_network.js
@@ -175,16 +175,18 @@ add_task(async function test_devtools_ne
   extension.sendMessage("navigate");
 
   // Wait till the navigation is complete and request
   // added into the net panel.
   await Promise.all([
     extension.awaitMessage("tabUpdated"),
     extension.awaitMessage("onNavigatedFired"),
     extension.awaitMessage("onRequestFinished"),
+    extension.awaitMessage("onRequestFinished-callbackExecuted"),
+    extension.awaitMessage("onRequestFinished-promiseResolved"),
     waitForRequestAdded(toolbox),
   ]);
 
   // Get HAR, it should not be empty now.
   const getHARPromise = extension.awaitMessage("getHAR-result");
   extension.sendMessage("getHAR");
   const getHARResult = await getHARPromise;
   is(getHARResult.log.entries.length, 1, "HAR log should not be empty");
--- a/devtools/client/netmonitor/src/connector/chrome-connector.js
+++ b/devtools/client/netmonitor/src/connector/chrome-connector.js
@@ -38,16 +38,20 @@ class ChromeConnector {
   pause() {
     this.disconnect();
   }
 
   resume() {
     this.setup();
   }
 
+  enableActions(enable) {
+    // TODO : implement.
+  }
+
   /**
    * currently all events are about "navigation" is not support on CDP
    */
   willNavigate() {
     this.actions.batchReset();
     this.actions.clearRequests();
   }
 
--- a/devtools/client/netmonitor/src/connector/firefox-connector.js
+++ b/devtools/client/netmonitor/src/connector/firefox-connector.js
@@ -122,16 +122,20 @@ class FirefoxConnector {
     }
     if (this.webConsoleClient) {
       this.webConsoleClient.off("networkEvent");
       this.webConsoleClient.off("networkEventUpdate");
       this.webConsoleClient.off("docEvent");
     }
   }
 
+  enableActions(enable) {
+    this.dataProvider.enableActions(enable);
+  }
+
   willNavigate() {
     if (!Services.prefs.getBoolPref("devtools.netmonitor.persistlog")) {
       this.actions.batchReset();
       this.actions.clearRequests();
     } else {
       // If the log is persistent, just clear all accumulated timing markers.
       this.actions.clearTimingMarkers();
     }
--- a/devtools/client/netmonitor/src/connector/firefox-data-provider.js
+++ b/devtools/client/netmonitor/src/connector/firefox-data-provider.js
@@ -17,16 +17,17 @@ const { fetchHeaders } = require("../uti
  * so it's possible to determine whether all has been fetched
  * or not.
  */
 class FirefoxDataProvider {
   constructor({webConsoleClient, actions}) {
     // Options
     this.webConsoleClient = webConsoleClient;
     this.actions = actions;
+    this.actionsEnabled = true;
 
     // Internal properties
     this.payloadQueue = new Map();
 
     // Map[key string => Promise] used by `requestData` to prevent requesting the same
     // request data twice.
     this.lazyRequestData = new Map();
 
@@ -34,33 +35,42 @@ class FirefoxDataProvider {
     this.getLongString = this.getLongString.bind(this);
 
     // Event handlers
     this.onNetworkEvent = this.onNetworkEvent.bind(this);
     this.onNetworkEventUpdate = this.onNetworkEventUpdate.bind(this);
   }
 
   /**
+   * Enable/disable firing redux actions (enabled by default).
+   *
+   * @param {boolean} enable Set to true to fire actions.
+   */
+  enableActions(enable) {
+    this.actionsEnabled = enable;
+  }
+
+  /**
    * Add a new network request to application state.
    *
    * @param {string} id request id
    * @param {object} data data payload will be added to application state
    */
   async addRequest(id, data) {
     let {
       method,
       url,
       isXHR,
       cause,
       startedDateTime,
       fromCache,
       fromServiceWorker,
     } = data;
 
-    if (this.actions.addRequest) {
+    if (this.actionsEnabled && this.actions.addRequest) {
       await this.actions.addRequest(id, {
         // Convert the received date/time string to a unix timestamp.
         startedMillis: Date.parse(startedDateTime),
         method,
         url,
         isXHR,
         cause,
 
@@ -115,17 +125,17 @@ class FirefoxDataProvider {
       responseContentObj,
       requestHeadersObj,
       responseHeadersObj,
       postDataObj,
       requestCookiesObj,
       responseCookiesObj
     );
 
-    if (this.actions.updateRequest) {
+    if (this.actionsEnabled && this.actions.updateRequest) {
       await this.actions.updateRequest(id, payload, true);
     }
 
     return payload;
   }
 
   async fetchResponseContent(responseContent) {
     let payload = {};
@@ -372,17 +382,17 @@ class FirefoxDataProvider {
 
     if (!payload.requestHeadersAvailable || !payload.requestCookiesAvailable ||
         !payload.eventTimingsAvailable || !payload.responseContentAvailable) {
       return;
     }
 
     this.payloadQueue.delete(actor);
 
-    if (this.actions.updateRequest) {
+    if (this.actionsEnabled && this.actions.updateRequest) {
       await this.actions.updateRequest(actor, payload, true);
     }
 
     // This event is fired only once per request, once all the properties are fetched
     // from `onNetworkEventUpdate`. There should be no more RDP requests after this.
     emit(EVENTS.PAYLOAD_READY, actor);
   }
 
@@ -409,17 +419,17 @@ class FirefoxDataProvider {
       return promise;
     }
     // Fetch the data
     promise = this._requestData(actor, method).then(async (payload) => {
       // Remove the request from the cache, any new call to requestData will fetch the
       // data again.
       this.lazyRequestData.delete(key);
 
-      if (this.actions.updateRequest) {
+      if (this.actionsEnabled && this.actions.updateRequest) {
         await this.actions.updateRequest(actor, {
           ...payload,
           // Lockdown *Available property once we fetch data from back-end.
           // Using this as a flag to prevent fetching arrived data again.
           [`${method}Available`]: false,
         }, true);
       }
 
--- a/devtools/client/netmonitor/src/connector/index.js
+++ b/devtools/client/netmonitor/src/connector/index.js
@@ -66,16 +66,20 @@ class Connector {
   pause() {
     return this.connector.pause();
   }
 
   resume() {
     return this.connector.resume();
   }
 
+  enableActions() {
+    this.connector.enableActions(...arguments);
+  }
+
   // Public API
 
   getLongString() {
     return this.connector.getLongString(...arguments);
   }
 
   getNetworkRequest() {
     return this.connector.getNetworkRequest(...arguments);
--- a/devtools/client/netmonitor/src/har/har-exporter.js
+++ b/devtools/client/netmonitor/src/har/har-exporter.js
@@ -190,28 +190,34 @@ const HarExporter = {
     let { connector } = options;
     let {
       getTabTarget,
     } = connector;
     let {
       form: { title, url }
     } = getTabTarget();
 
+    // Disconnect from redux actions/store.
+    connector.enableActions(false);
+
     options = {
       ...options,
       title: title || url,
       getString: connector.getLongString,
       getTimingMarker: connector.getTimingMarker,
       requestData: connector.requestData,
     };
 
     // Build HAR object from collected data.
     let builder = new HarBuilder(options);
     let result = await builder.build();
 
+    // Connect to redux actions again.
+    connector.enableActions(true);
+
     return result;
   },
 
   /**
    * Build JSON string from the HAR data object.
    */
   stringify: function (har) {
     if (!har) {