Bug 1404917 - Make FirefoxDataProvider.requestData more generic. r=Honza draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Thu, 26 Oct 2017 09:03:40 -0700
changeset 696266 206912a6926a88cd6b6fb20e8d29d419fcc865cc
parent 696265 d4c6b990a4c120afe3f3cecb9f05b241a616ea70
child 696267 a9194a08b707e27052ebad87734b03db69be75d8
push id88671
push userbmo:poirot.alex@gmail.com
push dateFri, 10 Nov 2017 10:12:58 +0000
reviewersHonza
bugs1404917
milestone58.0a1
Bug 1404917 - Make FirefoxDataProvider.requestData more generic. r=Honza MozReview-Commit-ID: 7XALj34m3XQ
devtools/client/netmonitor/src/connector/firefox-data-provider.js
--- a/devtools/client/netmonitor/src/connector/firefox-data-provider.js
+++ b/devtools/client/netmonitor/src/connector/firefox-data-provider.js
@@ -314,16 +314,19 @@ class FirefoxDataProvider {
       },
       startedDateTime,
     } = networkInfo;
 
     // Create tracking record for this request.
     this.rdpRequestMap.set(actor, {
       requestHeaders: false,
       requestCookies: false,
+      responseHeaders: false,
+      responseCookies: false,
+      securityInfo: false,
       eventTimings: false,
       responseContent: false,
     });
 
     this.addRequest(actor, {
       cause,
       fromCache,
       fromServiceWorker,
@@ -345,91 +348,54 @@ class FirefoxDataProvider {
    */
   onNetworkEventUpdate(type, data) {
     let { packet, networkInfo } = data;
     let { actor } = networkInfo;
     let { updateType } = packet;
 
     switch (updateType) {
       case "requestHeaders":
-        this.requestData(actor, updateType).then(response => {
-          this.onRequestHeaders(response)
-            .then(() => this.onDataReceived(actor, updateType));
-          emit(EVENTS.UPDATING_REQUEST_HEADERS, actor);
-        });
-        break;
       case "requestCookies":
-        this.requestData(actor, updateType).then(response => {
-          this.onRequestCookies(response)
-            .then(() => this.onDataReceived(actor, updateType));
-          emit(EVENTS.UPDATING_REQUEST_COOKIES, actor);
-        });
-        break;
       case "requestPostData":
-        this.requestData(actor, updateType).then(response => {
-          this.onRequestPostData(response)
-            .then(() => this.onDataReceived(actor, updateType));
-          emit(EVENTS.UPDATING_REQUEST_POST_DATA, actor);
-        });
+      case "responseHeaders":
+      case "responseCookies":
+        this.requestData(actor, updateType);
         break;
       case "securityInfo":
         this.updateRequest(actor, {
           securityState: networkInfo.securityInfo,
         }).then(() => {
-          this.requestData(actor, updateType).then(response => {
-            this.onSecurityInfo(response)
-              .then(() => this.onDataReceived(actor, updateType));
-            emit(EVENTS.UPDATING_SECURITY_INFO, actor);
-          });
-        });
-        break;
-      case "responseHeaders":
-        this.requestData(actor, updateType).then(response => {
-          this.onResponseHeaders(response)
-            .then(() => this.onDataReceived(actor, updateType));
-          emit(EVENTS.UPDATING_RESPONSE_HEADERS, actor);
-        });
-        break;
-      case "responseCookies":
-        this.requestData(actor, updateType).then(response => {
-          this.onResponseCookies(response)
-            .then(() => this.onDataReceived(actor, updateType));
-          emit(EVENTS.UPDATING_RESPONSE_COOKIES, actor);
+          this.requestData(actor, updateType);
         });
         break;
       case "responseStart":
         this.updateRequest(actor, {
           httpVersion: networkInfo.response.httpVersion,
           remoteAddress: networkInfo.response.remoteAddress,
           remotePort: networkInfo.response.remotePort,
           status: networkInfo.response.status,
           statusText: networkInfo.response.statusText,
           headersSize: networkInfo.response.headersSize
         }).then(() => {
           emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor);
         });
         break;
       case "responseContent":
-        this.requestData(actor, updateType).then(response => {
-          this.onResponseContent({
-            contentSize: networkInfo.response.bodySize,
-            transferredSize: networkInfo.response.transferredSize,
-            mimeType: networkInfo.response.content.mimeType
-          }, response).then(() => this.onDataReceived(actor, updateType));
-          emit(EVENTS.UPDATING_RESPONSE_CONTENT, actor);
+        this.updateRequest(actor, {
+          contentSize: networkInfo.response.bodySize,
+          transferredSize: networkInfo.response.transferredSize,
+          mimeType: networkInfo.response.content.mimeType
+        }).then(() => {
+          this.requestData(actor, updateType);
         });
         break;
       case "eventTimings":
         this.updateRequest(actor, { totalTime: networkInfo.totalTime })
           .then(() => {
-            this.requestData(actor, updateType).then(response => {
-              this.onEventTimings(response)
-                .then(() => this.onDataReceived(actor, updateType));
-              emit(EVENTS.UPDATING_EVENT_TIMINGS, actor);
-            });
+            this.requestData(actor, updateType);
           });
         break;
     }
 
     emit(EVENTS.NETWORK_EVENT_UPDATED, actor);
   }
 
   /**
@@ -442,61 +408,71 @@ class FirefoxDataProvider {
    * It also nicely returns a promise.
    *
    * @param {string} actor actor id (used as request id)
    * @param {string} method identifier of the data we want to fetch
    *
    * @return {Promise} return a promise resolved when data are received.
    */
   requestData(actor, method) {
-    let record = this.rdpRequestMap.get(actor);
-
     // All RDP requests related to the given actor will be collected
     // in the same record.
+    let record = this.rdpRequestMap.get(actor);
     if (!record) {
-      record = {};
+      dump(new Error().stack+"\n");
     }
 
-    // If data has been already requested return the same promise.
-    if (record.method) {
-      return record.method;
+    // If data has been already requested and is still a promise,
+    // returns the same promise.
+    if (record[method] instanceof Promise) {
+      return record[method];
     }
 
     // Calculate real name of the client getter.
-    let realMethodName = "get" + method.charAt(0).toUpperCase() +
+    let clientMethodName = "get" + method.charAt(0).toUpperCase() +
       method.slice(1);
+    // The name of the callback that processes request response
+    let callbackMethodName = "on" + method.charAt(0).toUpperCase() +
+      method.slice(1);
+    // And the event to fire before updating this data
+    let updatingEventName = "UPDATING_" + method.toUpperCase()
+      .replace(/(REQUEST|RESPONSE|EVENT|SECURITY)/, "$1_");
 
     // Request data from the backend.
-    let promise = new Promise((resolve, reject) => {
-      if (typeof this.webConsoleClient[realMethodName] == "function") {
-        this.webConsoleClient[realMethodName](actor, response => {
-          // Resolve incoming HTTP details data-promise.
-          resolve(response);
-        });
+    let promise = (async () => {
+      if (typeof this.webConsoleClient[clientMethodName] == "function") {
+        emit(EVENTS[updatingEventName], actor);
+        // Resolve incoming HTTP details data-promise.
+        let response = await this.webConsoleClient[clientMethodName](actor);
+        await this[callbackMethodName](response);
+
+        // Once we got the data toggle the Map item to `true` in order to
+        // make isRequestPayloadReady return `true` once all the data is fetched.
+        let record = this.rdpRequestMap.get(actor);
+        if (record) {
+          record[method] = true;
+        }
+
+        this.onDataReceived(actor, method);
+        return response;
       } else {
-        reject(new Error("Error: No such client method!"));
+        throw new Error("Error: No such client method '" + clientMethodName + "'!");
       }
-    });
+    })();
 
-    // Store the promise in order to know about RDP requests
-    // in progress.
+    // Store the promise in order to know about RDP requests in progress.
     record[method] = promise;
 
     return promise;
   }
 
   /**
    * Executed when new data are received from the backend.
    */
   async onDataReceived(actor, type) {
-    let record = this.rdpRequestMap.get(actor);
-    if (record) {
-      record[type] = true;
-    }
-
     if (this.isRequestPayloadReady(actor)) {
       let payloadFromQueue = this.getRequestFromQueue(actor).payload;
 
       // Clean up
       this.cleanUpQueue(actor);
       this.rdpRequestMap.delete(actor);
 
       let { updateRequest } = this.actions;
@@ -582,24 +558,27 @@ class FirefoxDataProvider {
     return this.updateRequest(response.from, {
       responseCookies: response
     }).then(() => {
       emit(EVENTS.RECEIVED_RESPONSE_COOKIES, response.from);
     });
   }
 
   /**
-   * Handles additional information received for a "responseContent" packet.
+   * Handles additional information received via "getResponseContent" request.
    *
-   * @param {object} data the message received from the server event.
    * @param {object} response the message received from the server.
    */
-  onResponseContent(data, response) {
-    let payload = Object.assign({ responseContent: response }, data);
-    return this.updateRequest(response.from, payload).then(() => {
+  onResponseContent(response) {
+    this.updateRequest(response.from, {
+      // We have to ensure passing mimeType as fetchResponseContent needs it from updateRequest.
+      // It will convert the LongString in `response.content.text` to a string.
+      mimeType: response.content.mimeType,
+      responseContent: response,
+    }).then(() => {
       emit(EVENTS.RECEIVED_RESPONSE_CONTENT, response.from);
     });
   }
 
   /**
    * Handles additional information received for a "eventTimings" packet.
    *
    * @param {object} response the message received from the server.