Bug 1350227 - [Performance] fetch data when request is selected draft
authorFred Lin <gasolin@mozilla.com>
Fri, 14 Apr 2017 11:44:19 +0800
changeset 562668 33c031f61f15525e2ac59e0331b21da4a26bc098
parent 562653 f77f3057b8ee04f1a7546e9cd69066d201e9a221
child 624282 c20af8b9546f7062d6332c1c704d79ee8ab055d9
push id54080
push userbmo:gasolin@mozilla.com
push dateFri, 14 Apr 2017 06:42:58 +0000
bugs1350227
milestone55.0a1
Bug 1350227 - [Performance] fetch data when request is selected MozReview-Commit-ID: 97TMHQinDdr
devtools/client/netmonitor/src/actions/index.js
devtools/client/netmonitor/src/actions/moz.build
devtools/client/netmonitor/src/actions/requests.js
devtools/client/netmonitor/src/actions/selection.js
devtools/client/netmonitor/src/netmonitor-controller.js
--- a/devtools/client/netmonitor/src/actions/index.js
+++ b/devtools/client/netmonitor/src/actions/index.js
@@ -2,22 +2,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const batching = require("./batching");
 const filters = require("./filters");
 const requests = require("./requests");
-const selection = require("./selection");
 const sort = require("./sort");
 const timingMarkers = require("./timing-markers");
 const ui = require("./ui");
 
 Object.assign(exports,
   batching,
   filters,
   requests,
-  selection,
   sort,
   timingMarkers,
   ui
 );
--- a/devtools/client/netmonitor/src/actions/moz.build
+++ b/devtools/client/netmonitor/src/actions/moz.build
@@ -2,13 +2,12 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DevToolsModules(
     'batching.js',
     'filters.js',
     'index.js',
     'requests.js',
-    'selection.js',
     'sort.js',
     'timing-markers.js',
     'ui.js',
 )
--- a/devtools/client/netmonitor/src/actions/requests.js
+++ b/devtools/client/netmonitor/src/actions/requests.js
@@ -4,21 +4,31 @@
 
 "use strict";
 
 const {
   ADD_REQUEST,
   CLEAR_REQUESTS,
   CLONE_SELECTED_REQUEST,
   REMOVE_SELECTED_CUSTOM_REQUEST,
+  SELECT_REQUEST,
   SEND_CUSTOM_REQUEST,
   UPDATE_REQUEST,
 } = require("../constants");
+const {
+  getDisplayedRequests,
+  getSelectedRequest,
+  getSortedRequests,
+} = require("../selectors/index");
+const { CurlUtils } = require("devtools/client/shared/curl");
+const { fetchHeaders } = require("../utils/request-utils");
+const { getLongString } = require("../utils/client");
 const { NetMonitorController } = require("../netmonitor-controller");
-const { getSelectedRequest } = require("../selectors/index");
+
+const PAGE_SIZE_ITEM_COUNT_RATIO = 5;
 
 function addRequest(id, data, batch) {
   return {
     type: ADD_REQUEST,
     id,
     data,
     meta: { batch },
   };
@@ -91,16 +101,177 @@ function removeSelectedCustomRequest() {
 }
 
 function clearRequests() {
   return {
     type: CLEAR_REQUESTS
   };
 }
 
+// update select request data asynchronizely
+async function updateRequestData(request) {
+  let {
+    responseCookies,
+    responseHeaders,
+    requestCookies,
+    requestHeaders,
+    requestPostData,
+  } = request;
+
+  // fetch requestHeaders
+  if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
+    let headers = await fetchHeaders(requestHeaders, getLongString);
+    if (headers) {
+      updateRequest(
+        request.id,
+        { requestHeaders: headers },
+        true,
+      );
+    }
+  }
+
+  // fetch responseHeaders
+  if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) {
+    let headers = await fetchHeaders(responseHeaders, getLongString);
+    if (headers) {
+      updateRequest(
+        request.id,
+        { responseHeaders: headers },
+        true,
+      );
+    }
+  }
+
+  // Search the POST data upload stream for request headers and add
+  // them as a separate property, different from the classic headers.
+  if (requestPostData && requestPostData.postData) {
+    let { text } = requestPostData.postData;
+    let postData = await getLongString(text);
+    const headers = CurlUtils.getHeadersFromMultipartText(postData);
+    const headersSize = headers.reduce((acc, { name, value }) => {
+      return acc + name.length + value.length + 2;
+    }, 0);
+    let payload = {};
+    requestPostData.postData.text = postData;
+    payload.requestPostData = Object.assign({}, requestPostData);
+    payload.requestHeadersFromUploadStream = { headers, headersSize };
+
+    updateRequest(request.id, payload, true);
+  }
+
+  // Fetch request and response cookies long value.
+  // Actor does not provide full sized cookie value when the value is too long
+  // To display values correctly, we need fetch them in each request.
+  if (requestCookies) {
+    let reqCookies = [];
+    // request store cookies in requestCookies or requestCookies.cookies
+    let cookies = requestCookies.cookies ?
+      requestCookies.cookies : requestCookies;
+    // make sure cookies is iterable
+    if (typeof cookies[Symbol.iterator] === "function") {
+      for (let cookie of cookies) {
+        reqCookies.push(Object.assign({}, cookie, {
+          value: await getLongString(cookie.value),
+        }));
+      }
+      if (reqCookies.length) {
+        updateRequest(request.id, { requestCookies: reqCookies }, true);
+      }
+    }
+  }
+
+  if (responseCookies) {
+    let resCookies = [];
+    // response store cookies in responseCookies or responseCookies.cookies
+    let cookies = responseCookies.cookies ?
+      responseCookies.cookies : responseCookies;
+    // make sure cookies is iterable
+    if (typeof cookies[Symbol.iterator] === "function") {
+      for (let cookie of cookies) {
+        resCookies.push(Object.assign({}, cookie, {
+          value: await getLongString(cookie.value),
+        }));
+      }
+      if (resCookies.length) {
+        updateRequest(request.id, { responseCookies: resCookies }, true);
+      }
+    }
+  }
+}
+
+/**
+ * Select request with a given id.
+ */
+function selectTheRequest(id) {
+  return {
+    type: SELECT_REQUEST,
+    id,
+  };
+}
+
+/**
+ * Select request with a given id with thunk.
+ */
+function selectRequest(id) {
+  return (dispatch, getState) => {
+    const selected = getSelectedRequest(getState());
+    if (selected) {
+      updateRequestData(selected);
+    }
+
+    dispatch(selectTheRequest(id));
+  };
+}
+
+/**
+ * Select request with a given index (sorted order)
+ */
+function selectRequestByIndex(index) {
+  return (dispatch, getState) => {
+    const requests = getSortedRequests(getState());
+    let itemId;
+    if (index >= 0 && index < requests.size) {
+      itemId = requests.get(index).id;
+    }
+    dispatch(selectRequest(itemId));
+  };
+}
+
+/**
+ * Move the selection up to down according to the "delta" parameter. Possible values:
+ * - Number: positive or negative, move up or down by specified distance
+ * - "PAGE_UP" | "PAGE_DOWN" (String): page up or page down
+ * - +Infinity | -Infinity: move to the start or end of the list
+ */
+function selectDelta(delta) {
+  return (dispatch, getState) => {
+    const state = getState();
+    const requests = getDisplayedRequests(state);
+
+    if (requests.isEmpty()) {
+      return;
+    }
+
+    const selIndex = requests.findIndex(r => r.id === state.requests.selectedId);
+
+    if (delta === "PAGE_DOWN") {
+      delta = Math.ceil(requests.size / PAGE_SIZE_ITEM_COUNT_RATIO);
+    } else if (delta === "PAGE_UP") {
+      delta = -Math.ceil(requests.size / PAGE_SIZE_ITEM_COUNT_RATIO);
+    }
+
+    const newIndex = Math.min(Math.max(0, selIndex + delta), requests.size - 1);
+    const newItem = requests.get(newIndex);
+    dispatch(selectRequest(newItem.id));
+  };
+}
+
 module.exports = {
   addRequest,
   clearRequests,
   cloneSelectedRequest,
   removeSelectedCustomRequest,
+  selectRequest,
+  selectRequestByIndex,
+  selectDelta,
   sendCustomRequest,
   updateRequest,
 };
deleted file mode 100644
--- a/devtools/client/netmonitor/src/actions/selection.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const { SELECT_REQUEST } = require("../constants");
-const {
-  getDisplayedRequests,
-  getSortedRequests,
-} = require("../selectors/index");
-
-const PAGE_SIZE_ITEM_COUNT_RATIO = 5;
-
-/**
- * Select request with a given id.
- */
-function selectRequest(id) {
-  return {
-    type: SELECT_REQUEST,
-    id,
-  };
-}
-
-/**
- * Select request with a given index (sorted order)
- */
-function selectRequestByIndex(index) {
-  return (dispatch, getState) => {
-    const requests = getSortedRequests(getState());
-    let itemId;
-    if (index >= 0 && index < requests.size) {
-      itemId = requests.get(index).id;
-    }
-    dispatch(selectRequest(itemId));
-  };
-}
-
-/**
- * Move the selection up to down according to the "delta" parameter. Possible values:
- * - Number: positive or negative, move up or down by specified distance
- * - "PAGE_UP" | "PAGE_DOWN" (String): page up or page down
- * - +Infinity | -Infinity: move to the start or end of the list
- */
-function selectDelta(delta) {
-  return (dispatch, getState) => {
-    const state = getState();
-    const requests = getDisplayedRequests(state);
-
-    if (requests.isEmpty()) {
-      return;
-    }
-
-    const selIndex = requests.findIndex(r => r.id === state.requests.selectedId);
-
-    if (delta === "PAGE_DOWN") {
-      delta = Math.ceil(requests.size / PAGE_SIZE_ITEM_COUNT_RATIO);
-    } else if (delta === "PAGE_UP") {
-      delta = -Math.ceil(requests.size / PAGE_SIZE_ITEM_COUNT_RATIO);
-    }
-
-    const newIndex = Math.min(Math.max(0, selIndex + delta), requests.size - 1);
-    const newItem = requests.get(newIndex);
-    dispatch(selectRequest(newItem.id));
-  };
-}
-
-module.exports = {
-  selectRequest,
-  selectRequestByIndex,
-  selectDelta,
-};
--- a/devtools/client/netmonitor/src/netmonitor-controller.js
+++ b/devtools/client/netmonitor/src/netmonitor-controller.js
@@ -1,25 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { TimelineFront } = require("devtools/shared/fronts/timeline");
-const { CurlUtils } = require("devtools/client/shared/curl");
 const { ACTIVITY_TYPE, EVENTS } = require("./constants");
 const {
   getRequestById,
   getDisplayedRequestById,
 } = require("./selectors/index");
-const {
-  fetchHeaders,
-  formDataURI,
-} = require("./utils/request-utils");
+const { formDataURI } = require("./utils/request-utils");
 const {
   getLongString,
   getWebConsoleClient,
   onFirefoxConnect,
   onFirefoxDisconnect,
 } = require("./utils/client");
 
 /**
@@ -224,16 +220,17 @@ var NetMonitorController = {
       }).then(standBy);
     }
     this._currentActivity = ACTIVITY_TYPE.NONE;
     return Promise.reject(new Error("Invalid activity type"));
   },
 
   /**
    * Selects the specified request in the waterfall and opens the details view.
+   * Used by webconsole
    *
    * @param string requestId
    *        The actor ID of the request to inspect.
    * @return object
    *         A promise resolved once the task finishes.
    */
   inspectRequest(requestId) {
     // Look for the request in the existing ones or wait for it to appear, if
@@ -425,48 +422,20 @@ NetworkEventsHandler.prototype = {
       },
       true
     )
     .then(() => window.emit(EVENTS.REQUEST_ADDED, id));
   },
 
   async updateRequest(id, data) {
     await this.actions.updateRequest(id, data, true);
-    let {
-      responseContent,
-      responseCookies,
-      responseHeaders,
-      requestCookies,
-      requestHeaders,
-      requestPostData,
-    } = data;
+    let { responseContent } = data;
     let request = getRequestById(window.gStore.getState(), id);
 
-    if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
-      let headers = await fetchHeaders(requestHeaders, getLongString);
-      if (headers) {
-        await this.actions.updateRequest(
-          id,
-          { requestHeaders: headers },
-          true,
-        );
-      }
-    }
-
-    if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) {
-      let headers = await fetchHeaders(responseHeaders, getLongString);
-      if (headers) {
-        await this.actions.updateRequest(
-          id,
-          { responseHeaders: headers },
-          true,
-        );
-      }
-    }
-
+    // fetch image
     if (request && responseContent && responseContent.content) {
       let { mimeType } = request;
       let { text, encoding } = responseContent.content;
       let response = await getLongString(text);
       let payload = {};
 
       if (mimeType.includes("image/")) {
         payload.responseContentDataUri = formDataURI(mimeType, encoding, response);
@@ -476,72 +445,16 @@ NetworkEventsHandler.prototype = {
       payload.responseContent = responseContent;
 
       await this.actions.updateRequest(id, payload, true);
 
       if (mimeType.includes("image/")) {
         window.emit(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
       }
     }
-
-    // Search the POST data upload stream for request headers and add
-    // them as a separate property, different from the classic headers.
-    if (requestPostData && requestPostData.postData) {
-      let { text } = requestPostData.postData;
-      let postData = await getLongString(text);
-      const headers = CurlUtils.getHeadersFromMultipartText(postData);
-      const headersSize = headers.reduce((acc, { name, value }) => {
-        return acc + name.length + value.length + 2;
-      }, 0);
-      let payload = {};
-      requestPostData.postData.text = postData;
-      payload.requestPostData = Object.assign({}, requestPostData);
-      payload.requestHeadersFromUploadStream = { headers, headersSize };
-
-      await this.actions.updateRequest(id, payload, true);
-    }
-
-    // Fetch request and response cookies long value.
-    // Actor does not provide full sized cookie value when the value is too long
-    // To display values correctly, we need fetch them in each request.
-    if (requestCookies) {
-      let reqCookies = [];
-      // request store cookies in requestCookies or requestCookies.cookies
-      let cookies = requestCookies.cookies ?
-        requestCookies.cookies : requestCookies;
-      // make sure cookies is iterable
-      if (typeof cookies[Symbol.iterator] === "function") {
-        for (let cookie of cookies) {
-          reqCookies.push(Object.assign({}, cookie, {
-            value: await getLongString(cookie.value),
-          }));
-        }
-        if (reqCookies.length) {
-          await this.actions.updateRequest(id, { requestCookies: reqCookies }, true);
-        }
-      }
-    }
-
-    if (responseCookies) {
-      let resCookies = [];
-      // response store cookies in responseCookies or responseCookies.cookies
-      let cookies = responseCookies.cookies ?
-        responseCookies.cookies : responseCookies;
-      // make sure cookies is iterable
-      if (typeof cookies[Symbol.iterator] === "function") {
-        for (let cookie of cookies) {
-          resCookies.push(Object.assign({}, cookie, {
-            value: await getLongString(cookie.value),
-          }));
-        }
-        if (resCookies.length) {
-          await this.actions.updateRequest(id, { responseCookies: resCookies }, true);
-        }
-      }
-    }
   },
 
   /**
    * The "networkEventUpdate" message type handler.
    *
    * @param string type
    *        Message type.
    * @param object packet