Bug 886067 - Netmonitor displays request sizes as "0 KB" after opening Console, r=msucan, a=lsblakk
authorVictor Porof <vporof@mozilla.com>
Wed, 26 Jun 2013 23:35:16 +0300
changeset 147800 5309228d21a6a19911dd5046b42e7fe3fd39334f
parent 147799 2d506101638507b16c5813975fe49a696c0be975
child 147801 7b87d1785e56b4c03b2882a127d470fe9f0948aa
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmsucan, lsblakk
bugs886067
milestone24.0a2
Bug 886067 - Netmonitor displays request sizes as "0 KB" after opening Console, r=msucan, a=lsblakk
browser/devtools/netmonitor/test/Makefile.in
browser/devtools/netmonitor/test/browser_net_post-data-02.js
browser/devtools/netmonitor/test/browser_net_req-resp-bodies.js
browser/devtools/netmonitor/test/html_post-raw-test-page.html
browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js
browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js
browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
browser/devtools/webconsole/test/browser_webconsole_netlogging.js
browser/devtools/webconsole/webconsole.js
toolkit/devtools/server/actors/webconsole.js
toolkit/devtools/webconsole/WebConsoleClient.jsm
--- a/browser/devtools/netmonitor/test/Makefile.in
+++ b/browser/devtools/netmonitor/test/Makefile.in
@@ -37,16 +37,17 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_net_sort-02.js \
 	browser_net_sort-03.js \
 	browser_net_filter-01.js \
 	browser_net_filter-02.js \
 	browser_net_filter-03.js \
 	browser_net_accessibility-01.js \
 	browser_net_accessibility-02.js \
 	browser_net_footer-summary.js \
+	browser_net_req-resp-bodies.js \
 	head.js \
 	$(NULL)
 
 MOCHITEST_BROWSER_PAGES = \
 	test-image.png \
 	html_simple-test-page.html \
 	html_navigate-test-page.html \
 	html_content-type-test-page.html \
--- a/browser/devtools/netmonitor/test/browser_net_post-data-02.js
+++ b/browser/devtools/netmonitor/test/browser_net_post-data-02.js
@@ -52,11 +52,11 @@ function test() {
       is(postScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
         "baz", "The second query param name was incorrect.");
       is(postScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
         "\"123\"", "The second query param value was incorrect.");
 
       teardown(aMonitor).then(finish);
     });
 
-    aDebuggee.performRequest();
+    aDebuggee.performRequests();
   });
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_req-resp-bodies.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test if request and response body logging stays on after opening the console.
+ */
+
+function test() {
+  initNetMonitor(JSON_LONG_URL).then(([aTab, aDebuggee, aMonitor]) => {
+    info("Starting test... ");
+
+    let { L10N, NetMonitorView } = aMonitor.panelWin;
+    let { RequestsMenu } = NetMonitorView;
+
+    RequestsMenu.lazyUpdate = false;
+
+    function verifyRequest(aOffset) {
+      verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOffset),
+        "GET", CONTENT_TYPE_SJS + "?fmt=json-long", {
+          status: 200,
+          statusText: "OK",
+          type: "json",
+          fullMimeType: "text/json; charset=utf-8",
+          size: L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(85975/1024, 2)),
+          time: true
+        });
+    }
+
+    waitForNetworkEvents(aMonitor, 1).then(() => {
+      verifyRequest(0);
+
+      aMonitor._toolbox.once("webconsole-selected", () => {
+        aMonitor._toolbox.once("netmonitor-selected", () => {
+
+          waitForNetworkEvents(aMonitor, 1).then(() => {
+            waitForNetworkEvents(aMonitor, 1).then(() => {
+              verifyRequest(1);
+              teardown(aMonitor).then(finish);
+            });
+
+            // Perform another batch of requests.
+            aDebuggee.performRequests();
+          });
+
+          // Reload debugee.
+          aDebuggee.location.reload();
+        });
+
+        // Switch back to the netmonitor.
+        aMonitor._toolbox.selectTool("netmonitor");
+      });
+
+      // Switch to the webconsole.
+      aMonitor._toolbox.selectTool("webconsole");
+    });
+
+    // Perform first batch of requests.
+    aDebuggee.performRequests();
+  });
+}
--- a/browser/devtools/netmonitor/test/html_post-raw-test-page.html
+++ b/browser/devtools/netmonitor/test/html_post-raw-test-page.html
@@ -17,17 +17,17 @@
         xhr.onreadystatechange = function() {
           if (this.readyState == this.DONE) {
             aCallback();
           }
         };
         xhr.send(aMessage);
       }
 
-      function performRequest() {
+      function performRequests() {
         var rawData = "Content-Type: application/x-www-form-urlencoded\r\n\r\nfoo=bar&baz=123";
         post("sjs_simple-test-server.sjs", rawData, function() {
           // Done.
         });
       }
     </script>
   </body>
 
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js
@@ -36,26 +36,18 @@ function performTest(lastFinishedRequest
 function test()
 {
   addTab("data:text/html;charset=utf-8,Web Console - bug 600183 test");
 
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
 
     openConsole(null, function(hud) {
-      hud.ui.saveRequestAndResponseBodies = true;
+      hud.ui.setSaveRequestAndResponseBodies(true).then(() => {
+        ok(hud.ui._saveRequestAndResponseBodies,
+          "The saveRequestAndResponseBodies property was successfully set.");
 
-      waitForSuccess({
-        name: "saveRequestAndResponseBodies update",
-        validatorFn: function()
-        {
-          return hud.ui.saveRequestAndResponseBodies;
-        },
-        successFn: function()
-        {
-          HUDService.lastFinishedRequestCallback = performTest;
-          content.location = TEST_URI;
-        },
-        failureFn: finishTest,
+        HUDService.lastFinishedRequestCallback = performTest;
+        content.location = TEST_URI;
       });
     });
   }, true);
 }
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js
@@ -65,50 +65,35 @@ function startTest()
 function onpopupshown2(aEvent)
 {
   menupopups[1].removeEventListener(aEvent.type, onpopupshown2, false);
 
   // By default bodies are not logged.
   isnot(menuitems[1].getAttribute("checked"), "true",
         "menuitems[1] is not checked");
 
-  ok(!huds[1].ui.saveRequestAndResponseBodies, "bodies are not logged");
+  ok(!huds[1].ui._saveRequestAndResponseBodies, "bodies are not logged");
 
   // Enable body logging.
-  huds[1].ui.saveRequestAndResponseBodies = true;
+  huds[1].ui.setSaveRequestAndResponseBodies(true).then(() => {
+    menupopups[1].hidePopup();
+  });
 
   menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
     menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
 
     info("menupopups[1] hidden");
 
     // Reopen the context menu.
-    menupopups[1].addEventListener("popupshown", onpopupshown2b, false);
-    executeSoon(function() {
-      menupopups[1].openPopup();
-    });
+    huds[1].ui.once("save-bodies-ui-toggled", () => testpopup2b(aEvent));
+    menupopups[1].openPopup();
   }, false);
-
-  waitForSuccess({
-    name: "saveRequestAndResponseBodies update",
-    validatorFn: function()
-    {
-      return huds[1].ui.saveRequestAndResponseBodies;
-    },
-    successFn: function()
-    {
-      menupopups[1].hidePopup();
-    },
-    failureFn: finishTest,
-  });
 }
 
-function onpopupshown2b(aEvent)
-{
-  menupopups[1].removeEventListener(aEvent.type, onpopupshown2b, false);
+function testpopup2b(aEvent) {
   is(menuitems[1].getAttribute("checked"), "true", "menuitems[1] is checked");
 
   menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
     menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
 
     info("menupopups[1] hidden");
 
     // Switch to tab 1 and open the Web Console context menu from there.
@@ -138,50 +123,36 @@ function onpopupshown1(aEvent)
 {
   menupopups[0].removeEventListener(aEvent.type, onpopupshown1, false);
 
   // The menuitem checkbox must not be in sync with the other tabs.
   isnot(menuitems[0].getAttribute("checked"), "true",
         "menuitems[0] is not checked");
 
   // Enable body logging for tab 1 as well.
-  huds[0].ui.saveRequestAndResponseBodies = true;
+  huds[0].ui.setSaveRequestAndResponseBodies(true).then(() => {
+    menupopups[0].hidePopup();
+  });
 
   // Close the menu, and switch back to tab 2.
   menupopups[0].addEventListener("popuphidden", function _onhidden(aEvent) {
     menupopups[0].removeEventListener(aEvent.type, _onhidden, false);
 
     info("menupopups[0] hidden");
 
     gBrowser.selectedTab = tabs[runCount*2 + 1];
     waitForFocus(function() {
       // Reopen the context menu from tab 2.
-      menupopups[1].addEventListener("popupshown", onpopupshown2c, false);
+      huds[1].ui.once("save-bodies-ui-toggled", () => testpopup2c(aEvent));
       menupopups[1].openPopup();
     }, tabs[runCount*2 + 1].linkedBrowser.contentWindow);
   }, false);
-
-  waitForSuccess({
-    name: "saveRequestAndResponseBodies update",
-    validatorFn: function()
-    {
-      return huds[0].ui.saveRequestAndResponseBodies;
-    },
-    successFn: function()
-    {
-      menupopups[0].hidePopup();
-    },
-    failureFn: finishTest,
-  });
 }
 
-function onpopupshown2c(aEvent)
-{
-  menupopups[1].removeEventListener(aEvent.type, onpopupshown2c, false);
-
+function testpopup2c(aEvent) {
   is(menuitems[1].getAttribute("checked"), "true", "menuitems[1] is checked");
 
   menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
     menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
 
     info("menupopups[1] hidden");
 
     // Done if on second run
@@ -198,15 +169,14 @@ function onpopupshown2c(aEvent)
         gBrowser.selectedTab = tabs[1];
         gBrowser.removeCurrentTab();
         gBrowser.selectedTab = tabs[0];
         gBrowser.removeCurrentTab();
         huds = menuitems = menupopups = tabs = null;
         executeSoon(finishTest);
       }
     });
-
   }, false);
 
   executeSoon(function() {
     menupopups[1].hidePopup();
   });
 }
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
@@ -16,31 +16,23 @@ function requestDoneCallback(aHttpReques
 {
   let status = aHttpRequest.response.status;
   lastFinishedRequests[status] = aHttpRequest;
 }
 
 function consoleOpened(hud)
 {
   webConsoleClient = hud.ui.webConsoleClient;
-  hud.ui.saveRequestAndResponseBodies = true;
+  hud.ui.setSaveRequestAndResponseBodies(true).then(() => {
+    ok(hud.ui._saveRequestAndResponseBodies,
+      "The saveRequestAndResponseBodies property was successfully set.");
 
-  waitForSuccess({
-    name: "saveRequestAndResponseBodies update",
-    validatorFn: function()
-    {
-      return hud.ui.saveRequestAndResponseBodies;
-    },
-    successFn: function()
-    {
-      HUDService.lastFinishedRequestCallback = requestDoneCallback;
-      waitForSuccess(waitForResponses);
-      content.location = TEST_URI;
-    },
-    failureFn: finishTest,
+    HUDService.lastFinishedRequestCallback = requestDoneCallback;
+    waitForSuccess(waitForResponses);
+    content.location = TEST_URI;
   });
 
   let waitForResponses = {
     name: "301 and 404 responses",
     validatorFn: function()
     {
       return "301" in lastFinishedRequests &&
              "404" in lastFinishedRequests;
--- a/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
@@ -80,26 +80,21 @@ function testPageLoad()
   };
 
   content.location = TEST_NETWORK_REQUEST_URI;
 }
 
 function testPageLoadBody()
 {
   // Turn on logging of request bodies and check again.
-  hud.ui.saveRequestAndResponseBodies = true;
+  hud.ui.setSaveRequestAndResponseBodies(true).then(() => {
+    ok(hud.ui._saveRequestAndResponseBodies,
+      "The saveRequestAndResponseBodies property was successfully set.");
 
-  waitForSuccess({
-    name: "saveRequestAndResponseBodies update",
-    validatorFn: function()
-    {
-      return hud.ui.saveRequestAndResponseBodies;
-    },
-    successFn: testPageLoadBodyAfterSettingUpdate,
-    failureFn: finishTest,
+    testPageLoadBodyAfterSettingUpdate();
   });
 }
 
 function testPageLoadBodyAfterSettingUpdate()
 {
   let loaded = false;
   let requestCallbackInvoked = false;
 
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -350,42 +350,73 @@ WebConsoleFrame.prototype = {
   /**
    * Getter for the debugger WebConsoleClient.
    * @type object
    */
   get webConsoleClient() this.proxy ? this.proxy.webConsoleClient : null,
 
   _destroyer: null,
 
+  // Used in tests.
   _saveRequestAndResponseBodies: false,
 
   /**
    * Tells whether to save the bodies of network requests and responses.
    * Disabled by default to save memory.
-   * @type boolean
+   *
+   * @return boolean
+   *         The saveRequestAndResponseBodies pref value.
    */
-  get saveRequestAndResponseBodies() this._saveRequestAndResponseBodies,
+  getSaveRequestAndResponseBodies:
+  function WCF_getSaveRequestAndResponseBodies() {
+    let deferred = Promise.defer();
+    let toGet = [
+      "NetworkMonitor.saveRequestAndResponseBodies"
+    ];
+
+    // Make sure the web console client connection is established first.
+    this.webConsoleClient.getPreferences(toGet, aResponse => {
+      if (!aResponse.error) {
+        this._saveRequestAndResponseBodies = aResponse.preferences[toGet[0]];
+        deferred.resolve(this._saveRequestAndResponseBodies);
+      }
+      else {
+        deferred.reject(aResponse.error);
+      }
+    });
+
+    return deferred.promise;
+  },
 
   /**
    * Setter for saving of network request and response bodies.
    *
    * @param boolean aValue
    *        The new value you want to set.
    */
-  set saveRequestAndResponseBodies(aValue) {
+  setSaveRequestAndResponseBodies:
+  function WCF_setSaveRequestAndResponseBodies(aValue) {
+    let deferred = Promise.defer();
     let newValue = !!aValue;
-    let preferences = {
+    let toSet = {
       "NetworkMonitor.saveRequestAndResponseBodies": newValue,
     };
 
-    this.webConsoleClient.setPreferences(preferences, function(aResponse) {
+    // Make sure the web console client connection is established first.
+    this.webConsoleClient.setPreferences(toSet, aResponse => {
       if (!aResponse.error) {
         this._saveRequestAndResponseBodies = newValue;
+        deferred.resolve(aResponse);
       }
-    }.bind(this));
+      else {
+        deferred.reject(aResponse.error);
+      }
+    });
+
+    return deferred.promise;
   },
 
   _persistLog: null,
 
   /**
    * Getter for the persistent logging preference. This value is cached per
    * instance to avoid reading the pref too often.
    * @type boolean
@@ -421,17 +452,16 @@ WebConsoleFrame.prototype = {
     if (this._initDefer) {
       return this._initDefer.promise;
     }
 
     this._initDefer = Promise.defer();
     this.proxy = new WebConsoleConnectionProxy(this, this.owner.target);
 
     this.proxy.connect().then(() => { // on success
-      this.saveRequestAndResponseBodies = this._saveRequestAndResponseBodies;
       this._initDefer.resolve(this);
     }, (aReason) => { // on failure
       let node = this.createMessageNode(CATEGORY_JS, SEVERITY_ERROR,
                                         aReason.error + ": " + aReason.message);
       this.outputMessage(CATEGORY_JS, node);
       this._initDefer.reject(aReason);
     }).then(() => {
       let id = WebConsoleUtils.supportsString(this.hudId);
@@ -474,52 +504,58 @@ WebConsoleFrame.prototype = {
     if (fontSize != 0) {
       fontSize = Math.max(MIN_FONT_SIZE, fontSize);
 
       this.outputNode.style.fontSize = fontSize + "px";
       this.completeNode.style.fontSize = fontSize + "px";
       this.inputNode.style.fontSize = fontSize + "px";
     }
 
+    let updateSaveBodiesPrefUI = (aElement) => {
+      this.getSaveRequestAndResponseBodies().then(aValue => {
+        aElement.setAttribute("checked", aValue);
+        this.emit("save-bodies-ui-toggled");
+      });
+    }
+
+    let reverseSaveBodiesPref = ({ target: aElement }) => {
+      this.getSaveRequestAndResponseBodies().then(aValue => {
+        this.setSaveRequestAndResponseBodies(!aValue);
+        aElement.setAttribute("checked", aValue);
+        this.emit("save-bodies-pref-reversed");
+      });
+    }
+
     let saveBodies = doc.getElementById("saveBodies");
-    saveBodies.addEventListener("command", function() {
-      this.saveRequestAndResponseBodies = !this.saveRequestAndResponseBodies;
-    }.bind(this));
-    saveBodies.setAttribute("checked", this.saveRequestAndResponseBodies);
+    saveBodies.addEventListener("click", reverseSaveBodiesPref);
     saveBodies.disabled = !this.getFilterState("networkinfo") &&
                           !this.getFilterState("network");
 
-    saveBodies.parentNode.addEventListener("popupshowing", function() {
-      saveBodies.setAttribute("checked", this.saveRequestAndResponseBodies);
+    let saveBodiesContextMenu = doc.getElementById("saveBodiesContextMenu");
+    saveBodiesContextMenu.addEventListener("click", reverseSaveBodiesPref);
+    saveBodiesContextMenu.disabled = !this.getFilterState("networkinfo") &&
+                                     !this.getFilterState("network");
+
+    saveBodies.parentNode.addEventListener("popupshowing", () => {
+      updateSaveBodiesPrefUI(saveBodies);
       saveBodies.disabled = !this.getFilterState("networkinfo") &&
                             !this.getFilterState("network");
-    }.bind(this));
-
-    // Remove this part when context menu entry is removed.
-    let saveBodiesContextMenu = doc.getElementById("saveBodiesContextMenu");
-    saveBodiesContextMenu.addEventListener("command", function() {
-      this.saveRequestAndResponseBodies = !this.saveRequestAndResponseBodies;
-    }.bind(this));
-    saveBodiesContextMenu.setAttribute("checked",
-                                       this.saveRequestAndResponseBodies);
-    saveBodiesContextMenu.disabled = !this.getFilterState("networkinfo") &&
-                                     !this.getFilterState("network");
-
-    saveBodiesContextMenu.parentNode.addEventListener("popupshowing", function() {
-      saveBodiesContextMenu.setAttribute("checked",
-                                         this.saveRequestAndResponseBodies);
+    });
+
+    saveBodiesContextMenu.parentNode.addEventListener("popupshowing", () => {
+      updateSaveBodiesPrefUI(saveBodiesContextMenu);
       saveBodiesContextMenu.disabled = !this.getFilterState("networkinfo") &&
                                        !this.getFilterState("network");
-    }.bind(this));
+    });
 
     let clearButton = doc.getElementsByClassName("webconsole-clear-console-button")[0];
-    clearButton.addEventListener("command", function WCF__onClearButton() {
+    clearButton.addEventListener("command", () => {
       this.owner._onClearButton();
       this.jsterm.clearOutput(true);
-    }.bind(this));
+    });
 
     this.jsterm = new JSTerm(this);
     this.jsterm.init();
     this.jsterm.inputNode.focus();
   },
 
   /**
    * Initialize the default filter preferences.
--- a/toolkit/devtools/server/actors/webconsole.js
+++ b/toolkit/devtools/server/actors/webconsole.js
@@ -653,16 +653,33 @@ WebConsoleActor.prototype =
     if (this._isGlobalActor) {
       Services.console.logStringMessage(null); // for the Error Console
       Services.console.reset();
     }
     return {};
   },
 
   /**
+   * The "getPreferences" request handler.
+   *
+   * @param object aRequest
+   *        The request message - which preferences need to be retrieved.
+   * @return object
+   *         The response message - a { key: value } object map.
+   */
+  onGetPreferences: function WCA_onGetPreferences(aRequest)
+  {
+    let prefs = Object.create(null);
+    for (let key of aRequest.preferences) {
+      prefs[key] = !!this._prefs[key];
+    }
+    return { preferences: prefs };
+  },
+
+  /**
    * The "setPreferences" request handler.
    *
    * @param object aRequest
    *        The request message - which preferences need to be updated.
    */
   onSetPreferences: function WCA_onSetPreferences(aRequest)
   {
     for (let key in aRequest.preferences) {
@@ -1119,17 +1136,18 @@ WebConsoleActor.prototype =
 WebConsoleActor.prototype.requestTypes =
 {
   startListeners: WebConsoleActor.prototype.onStartListeners,
   stopListeners: WebConsoleActor.prototype.onStopListeners,
   getCachedMessages: WebConsoleActor.prototype.onGetCachedMessages,
   evaluateJS: WebConsoleActor.prototype.onEvaluateJS,
   autocomplete: WebConsoleActor.prototype.onAutocomplete,
   clearMessagesCache: WebConsoleActor.prototype.onClearMessagesCache,
-  setPreferences: WebConsoleActor.prototype.onSetPreferences,
+  getPreferences: WebConsoleActor.prototype.onGetPreferences,
+  setPreferences: WebConsoleActor.prototype.onSetPreferences
 };
 
 /**
  * Creates an actor for a network event.
  *
  * @constructor
  * @param object aNetworkEvent
  *        The network event you want to use the actor for.
--- a/toolkit/devtools/webconsole/WebConsoleClient.jsm
+++ b/toolkit/devtools/webconsole/WebConsoleClient.jsm
@@ -143,16 +143,34 @@ WebConsoleClient.prototype = {
     let packet = {
       to: this._actor,
       type: "clearMessagesCache",
     };
     this._client.request(packet);
   },
 
   /**
+   * Get Web Console-related preferences on the server.
+   *
+   * @param object aPreferences
+   *        An object with the preferences you want to retrieve.
+   * @param function [aOnResponse]
+   *        Optional function to invoke when the response is received.
+   */
+  getPreferences: function WCC_getPreferences(aPreferences, aOnResponse)
+  {
+    let packet = {
+      to: this._actor,
+      type: "getPreferences",
+      preferences: aPreferences,
+    };
+    this._client.request(packet, aOnResponse);
+  },
+
+  /**
    * Set Web Console-related preferences on the server.
    *
    * @param object aPreferences
    *        An object with the preferences you want to change.
    * @param function [aOnResponse]
    *        Optional function to invoke when the response is received.
    */
   setPreferences: function WCC_setPreferences(aPreferences, aOnResponse)