Bug 768096 - Web Console remote debugging protocol support - Part 3: network logging; r=past,robcee

--HG--
rename : browser/devtools/webconsole/NetworkHelper.jsm => toolkit/devtools/webconsole/NetworkHelper.jsm
This commit is contained in:
Mihai Sucan 2012-09-27 13:51:45 +01:00
parent f468d13cdd
commit bc8c482314
17 changed files with 2579 additions and 377 deletions

View File

@ -18,7 +18,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm", tempScope);
Cu.import("resource://gre/modules/Services.jsm", tempScope);
Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm", tempScope);
Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tempScope);
Cu.import("resource:///modules/NetworkHelper.jsm", tempScope);
Cu.import("resource://gre/modules/devtools/NetworkHelper.jsm", tempScope);
Cu.import("resource://gre/modules/NetUtil.jsm", tempScope);
let XPCOMUtils = tempScope.XPCOMUtils;

View File

@ -529,28 +529,12 @@ WebConsole.prototype = {
*/
_asyncRequests: null,
/**
* Message names that the HUD listens for. These messages come from the remote
* Web Console content script.
*
* @private
* @type array
*/
_messageListeners: ["WebConsole:Initialized", "WebConsole:NetworkActivity",
"WebConsole:FileActivity", "WebConsole:LocationChange"],
/**
* The xul:panel that holds the Web Console when it is positioned as a window.
* @type nsIDOMElement
*/
consolePanel: null,
/**
* The current tab location.
* @type string
*/
contentLocation: "",
/**
* Getter for the xul:popupset that holds any popups we open.
* @type nsIDOMElement
@ -621,7 +605,6 @@ WebConsole.prototype = {
this.iframeWindow = this.iframe.contentWindow.wrappedJSObject;
this.ui = new this.iframeWindow.WebConsoleFrame(this, position);
this._setupMessageManager();
},
/**
@ -766,8 +749,8 @@ WebConsole.prototype = {
*/
getPanelTitle: function WC_getPanelTitle()
{
return l10n.getFormatStr("webConsoleWindowTitleAndURL",
[this.contentLocation]);
let url = this.ui ? this.ui.contentLocation : "";
return l10n.getFormatStr("webConsoleWindowTitleAndURL", [url]);
},
positions: {
@ -991,16 +974,16 @@ WebConsole.prototype = {
},
/**
* Handler for the "WebConsole:LocationChange" message. If the Web Console is
* Handler for page location changes. If the Web Console is
* opened in a panel the panel title is updated.
*
* @param object aMessage
* The message received from the content script. It needs to hold two
* properties: location and title.
* @param string aURI
* New page location.
* @param string aTitle
* New page title.
*/
onLocationChange: function WC_onLocationChange(aMessage)
onLocationChange: function WC_onLocationChange(aURI, aTitle)
{
this.contentLocation = aMessage.location;
if (this.consolePanel) {
this.consolePanel.label = this.getPanelTitle();
}
@ -1036,12 +1019,6 @@ WebConsole.prototype = {
*/
destroy: function WC_destroy(aOnDestroy)
{
this.sendMessageToContent("WebConsole:Destroy", {});
this._messageListeners.forEach(function(aName) {
this.messageManager.removeMessageListener(aName, this.ui);
}, this);
// Make sure that the console panel does not try to call
// deactivateHUDForContext() again.
this.consoleWindowUnregisterOnHide = false;

View File

@ -13,7 +13,6 @@ include $(DEPTH)/config/autoconf.mk
EXTRA_JS_MODULES = \
HUDService.jsm \
PropertyPanel.jsm \
NetworkHelper.jsm \
NetworkPanel.jsm \
AutocompletePopup.jsm \
$(NULL)

View File

@ -16,7 +16,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "mimeService", "@mozilla.org/mime;1",
"nsIMIMEService");
XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
"resource:///modules/NetworkHelper.jsm");
"resource://gre/modules/devtools/NetworkHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
@ -76,9 +76,17 @@ function NetworkPanel(aParent, aHttpActivity)
}, false);
// Set the document object and update the content once the panel is loaded.
this.panel.addEventListener("load", function onLoad() {
self.panel.removeEventListener("load", onLoad, true);
self.document = self.iframe.contentWindow.document;
this.iframe.addEventListener("load", function onLoad() {
if (!self.iframe) {
return;
}
self.iframe.removeEventListener("load", onLoad, true);
self.update();
}, true);
this.panel.addEventListener("popupshown", function onPopupShown() {
self.panel.removeEventListener("popupshown", onPopupShown, true);
self.update();
}, true);
@ -94,12 +102,6 @@ function NetworkPanel(aParent, aHttpActivity)
NetworkPanel.prototype =
{
/**
* Callback is called once the NetworkPanel is processed completely. Used by
* unit tests.
*/
isDoneCallback: null,
/**
* The current state of the output.
*/
@ -118,6 +120,20 @@ NetworkPanel.prototype =
_contentType: null,
/**
* Function callback invoked whenever the panel content is updated. This is
* used only by tests.
*
* @private
* @type function
*/
_onUpdate: null,
get document() {
return this.iframe && this.iframe.contentWindow ?
this.iframe.contentWindow.document : null;
},
/**
* Small helper function that is nearly equal to l10n.getFormatStr
* except that it prefixes aName with "NetworkPanel.".
@ -150,9 +166,8 @@ NetworkPanel.prototype =
return this._contentType;
}
let entry = this.httpActivity.log.entries[0];
let request = entry.request;
let response = entry.response;
let request = this.httpActivity.request;
let response = this.httpActivity.response;
let contentType = "";
let types = response.content ?
@ -236,7 +251,7 @@ NetworkPanel.prototype =
*/
get _isResponseCached()
{
return this.httpActivity.log.entries[0].response.status == 304;
return this.httpActivity.response.status == 304;
},
/**
@ -247,7 +262,7 @@ NetworkPanel.prototype =
*/
get _isRequestBodyFormData()
{
let requestBody = this.httpActivity.log.entries[0].request.postData.text;
let requestBody = this.httpActivity.request.postData.text;
return this._fromDataRegExp.test(requestBody);
},
@ -341,9 +356,8 @@ NetworkPanel.prototype =
*/
_displayRequestHeader: function NP__displayRequestHeader()
{
let entry = this.httpActivity.log.entries[0];
let request = entry.request;
let requestTime = new Date(entry.startedDateTime);
let request = this.httpActivity.request;
let requestTime = new Date(this.httpActivity.startedDateTime);
this._appendTextNode("headUrl", request.url);
this._appendTextNode("headMethod", request.method);
@ -364,8 +378,9 @@ NetworkPanel.prototype =
*
* @returns void
*/
_displayRequestBody: function NP__displayRequestBody() {
let postData = this.httpActivity.log.entries[0].request.postData;
_displayRequestBody: function NP__displayRequestBody()
{
let postData = this.httpActivity.request.postData;
this._displayNode("requestBody");
this._appendTextNode("requestBodyContent", postData.text);
},
@ -376,8 +391,9 @@ NetworkPanel.prototype =
*
* @returns void
*/
_displayRequestForm: function NP__processRequestForm() {
let postData = this.httpActivity.log.entries[0].request.postData.text;
_displayRequestForm: function NP__processRequestForm()
{
let postData = this.httpActivity.request.postData.text;
let requestBodyLines = postData.split("\n");
let formData = requestBodyLines[requestBodyLines.length - 1].
replace(/\+/g, " ").split("&");
@ -417,9 +433,8 @@ NetworkPanel.prototype =
*/
_displayResponseHeader: function NP__displayResponseHeader()
{
let entry = this.httpActivity.log.entries[0];
let timing = entry.timings;
let response = entry.response;
let timing = this.httpActivity.timings;
let response = this.httpActivity.response;
this._appendTextNode("headStatus",
[response.httpVersion, response.status,
@ -453,16 +468,16 @@ NetworkPanel.prototype =
_displayResponseImage: function NP__displayResponseImage()
{
let self = this;
let entry = this.httpActivity.log.entries[0];
let timing = entry.timings;
let request = entry.request;
let timing = this.httpActivity.timings;
let request = this.httpActivity.request;
let cached = "";
if (this._isResponseCached) {
cached = "Cached";
}
let imageNode = this.document.getElementById("responseImage" + cached +"Node");
let imageNode = this.document.getElementById("responseImage" +
cached + "Node");
imageNode.setAttribute("src", request.url);
// This function is called to set the imageInfo.
@ -498,9 +513,8 @@ NetworkPanel.prototype =
*/
_displayResponseBody: function NP__displayResponseBody()
{
let entry = this.httpActivity.log.entries[0];
let timing = entry.timings;
let response = entry.response;
let timing = this.httpActivity.timings;
let response = this.httpActivity.response;
let cached = this._isResponseCached ? "Cached" : "";
this._appendTextNode("responseBody" + cached + "Info",
@ -519,7 +533,7 @@ NetworkPanel.prototype =
*/
_displayResponseBodyUnknownType: function NP__displayResponseBodyUnknownType()
{
let timing = this.httpActivity.log.entries[0].timings;
let timing = this.httpActivity.timings;
this._displayNode("responseBodyUnknownType");
this._appendTextNode("responseBodyUnknownTypeInfo",
@ -537,7 +551,7 @@ NetworkPanel.prototype =
*/
_displayNoResponseBody: function NP_displayNoResponseBody()
{
let timing = this.httpActivity.log.entries[0].timings;
let timing = this.httpActivity.timings;
this._displayNode("responseNoBody");
this._appendTextNode("responseNoBodyInfo",
@ -557,11 +571,10 @@ NetworkPanel.prototype =
return;
}
let stages = this.httpActivity.meta.stages;
let entry = this.httpActivity.log.entries[0];
let timing = entry.timings;
let request = entry.request;
let response = entry.response;
let updates = this.httpActivity.updates;
let timing = this.httpActivity.timings;
let request = this.httpActivity.request;
let response = this.httpActivity.response;
switch (this._state) {
case this._INIT:
@ -571,7 +584,7 @@ NetworkPanel.prototype =
case this._DISPLAYED_REQUEST_HEADER:
// Process the request body if there is one.
if (!this.httpActivity.meta.discardRequestBody && request.postData) {
if (!this.httpActivity.discardRequestBody && request.postData.text) {
// Check if we send some form data. If so, display the form data special.
if (this._isRequestBodyFormData) {
this._displayRequestForm();
@ -584,9 +597,6 @@ NetworkPanel.prototype =
// FALL THROUGH
case this._DISPLAYED_REQUEST_BODY:
// There is always a response header. Therefore we can skip here if
// we don't have a response header yet and don't have to try updating
// anything else in the NetworkPanel.
if (!response.headers.length || !Object.keys(timing).length) {
break;
}
@ -595,13 +605,13 @@ NetworkPanel.prototype =
// FALL THROUGH
case this._DISPLAYED_RESPONSE_HEADER:
if (stages.indexOf("REQUEST_STOP") == -1 ||
stages.indexOf("TRANSACTION_CLOSE") == -1) {
if (updates.indexOf("responseContent") == -1 ||
updates.indexOf("eventTimings") == -1) {
break;
}
this._state = this._TRANSITION_CLOSED;
if (this.httpActivity.meta.discardResponseBody) {
if (this.httpActivity.discardResponseBody) {
break;
}
@ -617,9 +627,12 @@ NetworkPanel.prototype =
else if (response.content.text) {
this._displayResponseBody();
}
break;
}
if (this._onUpdate) {
this._onUpdate();
}
}
}

View File

@ -10,10 +10,12 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-599725-response-headers.sjs";
function performTest(lastFinishedRequest)
function performTest(lastFinishedRequest, aConsole)
{
ok(lastFinishedRequest, "page load was logged");
let headers = null;
function readHeader(aName)
{
for (let header of headers) {
@ -24,13 +26,16 @@ function performTest(lastFinishedRequest)
return null;
}
let headers = lastFinishedRequest.log.entries[0].response.headers;
ok(headers, "we have the response headers");
ok(!readHeader("Content-Type"), "we do not have the Content-Type header");
isnot(readHeader("Content-Length"), 60, "Content-Length != 60");
aConsole.webConsoleClient.getResponseHeaders(lastFinishedRequest.actor,
function (aResponse) {
headers = aResponse.headers;
ok(headers, "we have the response headers");
ok(!readHeader("Content-Type"), "we do not have the Content-Type header");
isnot(readHeader("Content-Length"), 60, "Content-Length != 60");
executeSoon(finishTest);
});
HUDService.lastFinishedRequestCallback = null;
executeSoon(finishTest);
}
function test()

View File

@ -10,39 +10,49 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-600183-charset.html";
function performTest(lastFinishedRequest)
function performTest(lastFinishedRequest, aConsole)
{
ok(lastFinishedRequest, "charset test page was loaded and logged");
let body = lastFinishedRequest.log.entries[0].response.content.text;
ok(body, "we have the response body");
aConsole.webConsoleClient.getResponseContent(lastFinishedRequest.actor,
function (aResponse) {
ok(!aResponse.contentDiscarded, "response body was not discarded");
let chars = "\u7684\u95ee\u5019!"; // 的问候!
isnot(body.indexOf("<p>" + chars + "</p>"), -1,
"found the chinese simplified string");
let body = aResponse.content.text;
ok(body, "we have the response body");
let chars = "\u7684\u95ee\u5019!"; // 的问候!
isnot(body.indexOf("<p>" + chars + "</p>"), -1,
"found the chinese simplified string");
executeSoon(finishTest);
});
HUDService.lastFinishedRequestCallback = null;
executeSoon(finishTest);
}
function test()
{
addTab("data:text/html;charset=utf-8,Web Console - bug 600183 test");
let initialLoad = true;
browser.addEventListener("load", function onLoad() {
if (initialLoad) {
openConsole(null, function(hud) {
browser.removeEventListener("load", onLoad, true);
hud.ui.saveRequestAndResponseBodies = true;
HUDService.lastFinishedRequestCallback = performTest;
openConsole(null, function(hud) {
hud.ui.saveRequestAndResponseBodies = true;
content.location = TEST_URI;
waitForSuccess({
name: "saveRequestAndResponseBodies update",
validatorFn: function()
{
return hud.ui.saveRequestAndResponseBodies;
},
successFn: function()
{
HUDService.lastFinishedRequestCallback = performTest;
content.location = TEST_URI;
},
failureFn: finishTest,
});
initialLoad = false;
} else {
browser.removeEventListener("load", onLoad, true);
}
});
}, true);
}

View File

@ -86,8 +86,17 @@ function onpopupshown2(aEvent)
});
}, false);
executeSoon(function() {
menupopups[1].hidePopup();
waitForSuccess({
name: "saveRequestAndResponseBodies update",
validatorFn: function()
{
return huds[1].ui.saveRequestAndResponseBodies;
},
successFn: function()
{
menupopups[1].hidePopup();
},
failureFn: finishTest,
});
}
@ -147,8 +156,17 @@ function onpopupshown1(aEvent)
}, tabs[runCount*2 + 1].linkedBrowser.contentWindow);
}, false);
executeSoon(function() {
menupopups[0].hidePopup();
waitForSuccess({
name: "saveRequestAndResponseBodies update",
validatorFn: function()
{
return huds[0].ui.saveRequestAndResponseBodies;
},
successFn: function()
{
menupopups[0].hidePopup();
},
failureFn: finishTest,
});
}

View File

@ -10,20 +10,86 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-630733-response-redirect-headers.sjs";
let lastFinishedRequests = {};
let webConsoleClient;
function requestDoneCallback(aHttpRequest)
function requestDoneCallback(aHttpRequest )
{
let status = aHttpRequest.log.entries[0].response.status;
let status = aHttpRequest.response.status;
lastFinishedRequests[status] = aHttpRequest;
}
function performTest(aEvent)
function consoleOpened(hud)
{
webConsoleClient = hud.ui.webConsoleClient;
hud.ui.saveRequestAndResponseBodies = true;
waitForSuccess({
name: "saveRequestAndResponseBodies update",
validatorFn: function()
{
return hud.ui.saveRequestAndResponseBodies;
},
successFn: function()
{
HUDService.lastFinishedRequestCallback = requestDoneCallback;
waitForSuccess(waitForResponses);
content.location = TEST_URI;
},
failureFn: finishTest,
});
let waitForResponses = {
name: "301 and 404 responses",
validatorFn: function()
{
return "301" in lastFinishedRequests &&
"404" in lastFinishedRequests;
},
successFn: getHeaders,
failureFn: finishTest,
};
}
function getHeaders()
{
HUDService.lastFinishedRequestCallback = null;
ok("301" in lastFinishedRequests, "request 1: 301 Moved Permanently");
ok("404" in lastFinishedRequests, "request 2: 404 Not found");
webConsoleClient.getResponseHeaders(lastFinishedRequests["301"].actor,
function (aResponse) {
lastFinishedRequests["301"].response.headers = aResponse.headers;
webConsoleClient.getResponseHeaders(lastFinishedRequests["404"].actor,
function (aResponse) {
lastFinishedRequests["404"].response.headers = aResponse.headers;
executeSoon(getContent);
});
});
}
function getContent()
{
webConsoleClient.getResponseContent(lastFinishedRequests["301"].actor,
function (aResponse) {
lastFinishedRequests["301"].response.content = aResponse.content;
lastFinishedRequests["301"].discardResponseBody = aResponse.contentDiscarded;
webConsoleClient.getResponseContent(lastFinishedRequests["404"].actor,
function (aResponse) {
lastFinishedRequests["404"].response.content = aResponse.content;
lastFinishedRequests["404"].discardResponseBody =
aResponse.contentDiscarded;
webConsoleClient = null;
executeSoon(performTest);
});
});
}
function performTest()
{
function readHeader(aName)
{
for (let header of headers) {
@ -34,7 +100,7 @@ function performTest(aEvent)
return null;
}
let headers = lastFinishedRequests["301"].log.entries[0].response.headers;
let headers = lastFinishedRequests["301"].response.headers;
is(readHeader("Content-Type"), "text/html",
"we do have the Content-Type header");
is(readHeader("Content-Length"), 71, "Content-Length is correct");
@ -42,14 +108,17 @@ function performTest(aEvent)
"Content-Length is correct");
is(readHeader("x-foobar-bug630733"), "bazbaz",
"X-Foobar-bug630733 is correct");
let body = lastFinishedRequests["301"].log.entries[0].response.content;
ok(!body.text, "body discarded for request 1");
headers = lastFinishedRequests["404"].log.entries[0].response.headers;
let body = lastFinishedRequests["301"].response.content;
ok(!body.text, "body discarded for request 1");
ok(lastFinishedRequests["301"].discardResponseBody,
"body discarded for request 1 (confirmed)");
headers = lastFinishedRequests["404"].response.headers;
ok(!readHeader("Location"), "no Location header");
ok(!readHeader("x-foobar-bug630733"), "no X-Foobar-bug630733 header");
body = lastFinishedRequests["404"].log.entries[0].response.content.text;
body = lastFinishedRequests["404"].response.content.text;
isnot(body.indexOf("404"), -1,
"body is correct for request 2");
@ -61,19 +130,8 @@ function test()
{
addTab("data:text/html;charset=utf-8,<p>Web Console test for bug 630733");
browser.addEventListener("load", function onLoad1(aEvent) {
browser.removeEventListener(aEvent.type, onLoad1, true);
openConsole(null, function(hud) {
hud.ui.saveRequestAndResponseBodies = true;
HUDService.lastFinishedRequestCallback = requestDoneCallback;
browser.addEventListener("load", function onLoad2(aEvent) {
browser.removeEventListener(aEvent.type, onLoad2, true);
executeSoon(performTest);
}, true);
content.location = TEST_URI;
});
browser.addEventListener("load", function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, onLoad, true);
openConsole(null, consoleOpened);
}, true);
}

View File

@ -25,7 +25,7 @@ function test()
hud = aHud;
HUDService.lastFinishedRequestCallback = function(aRequest) {
lastRequest = aRequest.log.entries[0];
lastRequest = aRequest;
if (requestCallback) {
requestCallback();
}

View File

@ -21,7 +21,6 @@ const TEST_DATA_JSON_CONTENT =
let lastRequest = null;
let requestCallback = null;
let lastActivity = null;
function test()
{
@ -33,19 +32,34 @@ function test()
openConsole(null, function(aHud) {
hud = aHud;
HUDService.lastFinishedRequestCallback = function(aRequest) {
lastRequest = aRequest.log.entries[0];
lastActivity = aRequest;
if (requestCallback) {
requestCallback();
}
};
HUDService.lastFinishedRequestCallback = requestCallbackWrapper;
executeSoon(testPageLoad);
});
}, true);
}
function requestCallbackWrapper(aRequest)
{
lastRequest = aRequest;
hud.ui.webConsoleClient.getResponseContent(lastRequest.actor,
function(aResponse) {
lastRequest.response.content = aResponse.content;
lastRequest.discardResponseBody = aResponse.contentDiscarded;
hud.ui.webConsoleClient.getRequestPostData(lastRequest.actor,
function(aResponse) {
lastRequest.request.postData = aResponse.postData;
lastRequest.discardRequestBody = aResponse.postDataDiscarded;
if (requestCallback) {
requestCallback();
}
});
});
}
function testPageLoad()
{
requestCallback = function() {
@ -55,8 +69,10 @@ function testPageLoad()
is(lastRequest.request.url, TEST_NETWORK_REQUEST_URI,
"Logged network entry is page load");
is(lastRequest.request.method, "GET", "Method is correct");
ok(!lastRequest.request.postData, "No request body was stored");
ok(!lastRequest.request.postData.text, "No request body was stored");
ok(lastRequest.discardRequestBody, "Request body was discarded");
ok(!lastRequest.response.content.text, "No response body was stored");
ok(lastRequest.discardResponseBody, "Response body was discarded");
lastRequest = null;
requestCallback = null;
@ -67,14 +83,29 @@ function testPageLoad()
}
function testPageLoadBody()
{
// Turn on logging of request bodies and check again.
hud.ui.saveRequestAndResponseBodies = true;
waitForSuccess({
name: "saveRequestAndResponseBodies update",
validatorFn: function()
{
return hud.ui.saveRequestAndResponseBodies;
},
successFn: testPageLoadBodyAfterSettingUpdate,
failureFn: finishTest,
});
}
function testPageLoadBodyAfterSettingUpdate()
{
let loaded = false;
let requestCallbackInvoked = false;
// Turn on logging of request bodies and check again.
hud.ui.saveRequestAndResponseBodies = true;
requestCallback = function() {
ok(lastRequest, "Page load was logged again");
ok(!lastRequest.discardResponseBody, "Response body was not discarded");
is(lastRequest.response.content.text.indexOf("<!DOCTYPE HTML>"), 0,
"Response body's beginning is okay");
@ -104,7 +135,8 @@ function testXhrGet()
requestCallback = function() {
ok(lastRequest, "testXhrGet() was logged");
is(lastRequest.request.method, "GET", "Method is correct");
ok(!lastRequest.request.postData, "No request body was sent");
ok(!lastRequest.request.postData.text, "No request body was sent");
ok(!lastRequest.discardRequestBody, "Request body was not discarded");
is(lastRequest.response.content.text, TEST_DATA_JSON_CONTENT,
"Response is correct");
@ -165,19 +197,18 @@ function testNetworkPanel()
{
// Open the NetworkPanel. The functionality of the NetworkPanel is tested
// within separate test files.
let networkPanel = hud.ui.openNetworkPanel(hud.ui.filterBox, lastActivity);
is(networkPanel, hud.ui.filterBox._netPanel,
"Network panel stored on anchor node");
let networkPanel = hud.ui.openNetworkPanel(hud.ui.filterBox, lastRequest);
networkPanel.panel.addEventListener("load", function onLoad(aEvent) {
networkPanel.panel.removeEventListener(aEvent.type, onLoad, true);
networkPanel.panel.addEventListener("popupshown", function onPopupShown() {
networkPanel.panel.removeEventListener("popupshown", onPopupShown, true);
is(hud.ui.filterBox._netPanel, networkPanel,
"Network panel stored on anchor node");
ok(true, "NetworkPanel was opened");
// All tests are done. Shutdown.
networkPanel.panel.hidePopup();
lastRequest = null;
lastActivity = null;
HUDService.lastFinishedRequestCallback = null;
executeSoon(finishTest);
}, true);

View File

@ -65,42 +65,36 @@ function testGen() {
let filterBox = hud.ui.filterBox;
let httpActivity = {
meta: {
stages: [],
discardRequestBody: true,
discardResponseBody: true,
updates: [],
discardRequestBody: true,
discardResponseBody: true,
startedDateTime: (new Date()).toISOString(),
request: {
url: "http://www.testpage.com",
method: "GET",
cookies: [],
headers: [
{ name: "foo", value: "bar" },
],
},
log: {
entries: [{
startedDateTime: (new Date()).toISOString(),
request: {
url: "http://www.testpage.com",
method: "GET",
cookies: [],
headers: [
{ name: "foo", value: "bar" },
],
},
response: {
headers: [],
content: {},
},
timings: {},
}],
response: {
headers: [],
content: {},
},
timings: {},
};
let entry = httpActivity.log.entries[0];
let networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
is(filterBox._netPanel, networkPanel,
"Network panel stored on the anchor object");
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -123,8 +117,8 @@ function testGen() {
// Test request body.
info("test 2: request body");
httpActivity.meta.discardRequestBody = false;
entry.request.postData = { text: "hello world" };
httpActivity.discardRequestBody = false;
httpActivity.request.postData = { text: "hello world" };
networkPanel.update();
checkIsVisible(networkPanel, {
@ -141,12 +135,12 @@ function testGen() {
// Test response header.
info("test 3: response header");
entry.timings.wait = 10;
entry.response.httpVersion = "HTTP/3.14";
entry.response.status = 999;
entry.response.statusText = "earthquake win";
entry.response.content.mimeType = "text/html";
entry.response.headers.push(
httpActivity.timings.wait = 10;
httpActivity.response.httpVersion = "HTTP/3.14";
httpActivity.response.status = 999;
httpActivity.response.statusText = "earthquake win";
httpActivity.response.content.mimeType = "text/html";
httpActivity.response.headers.push(
{ name: "Content-Type", value: "text/html" },
{ name: "leaveHouses", value: "true" }
);
@ -170,8 +164,8 @@ function testGen() {
info("test 4");
httpActivity.meta.discardResponseBody = false;
entry.timings.receive = 2;
httpActivity.discardResponseBody = false;
httpActivity.timings.receive = 2;
networkPanel.update();
checkIsVisible(networkPanel, {
@ -187,7 +181,7 @@ function testGen() {
info("test 5");
httpActivity.meta.stages.push("REQUEST_STOP", "TRANSACTION_CLOSE");
httpActivity.updates.push("responseContent", "eventTimings");
networkPanel.update();
checkNodeContent(networkPanel, "responseNoBodyInfo", "2ms");
@ -205,20 +199,22 @@ function testGen() {
// Second run: Test for cookies and response body.
info("test 6: cookies and response body");
entry.request.cookies.push(
httpActivity.request.cookies.push(
{ name: "foo", value: "bar" },
{ name: "hello", value: "world" }
);
entry.response.content.text = "get out here";
httpActivity.response.content.text = "get out here";
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
is(filterBox._netPanel, networkPanel,
"Network panel stored on httpActivity object");
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -242,15 +238,17 @@ function testGen() {
// Check image request.
info("test 7: image request");
entry.response.headers[1].value = "image/png";
entry.response.content.mimeType = "image/png";
entry.request.url = TEST_IMG;
httpActivity.response.headers[1].value = "image/png";
httpActivity.response.content.mimeType = "image/png";
httpActivity.request.url = TEST_IMG;
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -291,15 +289,17 @@ function testGen() {
// Check cached image request.
info("test 8: cached image request");
entry.response.httpVersion = "HTTP/1.1";
entry.response.status = 304;
entry.response.statusText = "Not Modified";
httpActivity.response.httpVersion = "HTTP/1.1";
httpActivity.response.status = 304;
httpActivity.response.statusText = "Not Modified";
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -321,17 +321,19 @@ function testGen() {
// Test sent form data.
info("test 9: sent form data");
entry.request.postData.text = [
httpActivity.request.postData.text = [
"Content-Type: application/x-www-form-urlencoded",
"Content-Length: 59",
"name=rob&age=20"
].join("\n");
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -352,13 +354,15 @@ function testGen() {
// Test no space after Content-Type:
info("test 10: no space after Content-Type header in post data");
entry.request.postData.text = "Content-Type:application/x-www-form-urlencoded\n";
httpActivity.request.postData.text = "Content-Type:application/x-www-form-urlencoded\n";
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -379,16 +383,18 @@ function testGen() {
info("test 11: cached data");
entry.request.url = TEST_ENCODING_ISO_8859_1;
entry.response.headers[1].value = "application/json";
entry.response.content.mimeType = "application/json";
entry.response.content.text = "my cached data is here!";
httpActivity.request.url = TEST_ENCODING_ISO_8859_1;
httpActivity.response.headers[1].value = "application/json";
httpActivity.response.content.mimeType = "application/json";
httpActivity.response.content.text = "my cached data is here!";
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;
@ -412,14 +418,16 @@ function testGen() {
// Test a response with a content type that can't be displayed in the
// NetworkPanel.
info("test 12: unknown content type");
entry.response.headers[1].value = "application/x-shockwave-flash";
entry.response.content.mimeType = "application/x-shockwave-flash";
httpActivity.response.headers[1].value = "application/x-shockwave-flash";
httpActivity.response.content.mimeType = "application/x-shockwave-flash";
networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
networkPanel.panel.addEventListener("load", function onLoad() {
networkPanel.panel.removeEventListener("load", onLoad, true);
testDriver.next();
}, true);
networkPanel._onUpdate = function() {
networkPanel._onUpdate = null;
executeSoon(function() {
testDriver.next();
});
};
yield;

View File

@ -216,13 +216,6 @@ WebConsoleFrame.prototype = {
*/
proxy: null,
/**
* Tells if the Web Console initialization via message manager completed.
* @private
* @type boolean
*/
_messageManagerInitComplete: false,
/**
* Getter for the xul:popupset that holds any popups we open.
* @type nsIDOMElement
@ -290,6 +283,12 @@ WebConsoleFrame.prototype = {
*/
groupDepth: 0,
/**
* The current tab location.
* @type string
*/
contentLocation: "",
/**
* The JSTerm object that manage the console's input.
* @see JSTerm
@ -331,16 +330,16 @@ WebConsoleFrame.prototype = {
* The new value you want to set.
*/
set saveRequestAndResponseBodies(aValue) {
this._saveRequestAndResponseBodies = aValue;
let message = {
preferences: {
"NetworkMonitor.saveRequestAndResponseBodies":
this._saveRequestAndResponseBodies,
},
let newValue = !!aValue;
let preferences = {
"NetworkMonitor.saveRequestAndResponseBodies": newValue,
};
this.owner.sendMessageToContent("WebConsole:SetPreferences", message);
this.webConsoleClient.setPreferences(preferences, function(aResponse) {
if (!aResponse.error) {
this._saveRequestAndResponseBodies = newValue;
}
}.bind(this));
},
/**
@ -352,9 +351,8 @@ WebConsoleFrame.prototype = {
this.proxy = new WebConsoleConnectionProxy(this);
this.proxy.initServer();
this.proxy.connect(function() {
if (this._messageManagerInitComplete) {
this._onInitComplete();
}
this.saveRequestAndResponseBodies = this._saveRequestAndResponseBodies;
this._onInitComplete();
}.bind(this));
},
@ -653,50 +651,6 @@ WebConsoleFrame.prototype = {
}
},
/**
* Handler for all of the messages coming from the Web Console content script.
*
* @private
* @param object aMessage
* A MessageManager object that holds the remote message.
*/
receiveMessage: function WCF_receiveMessage(aMessage)
{
if (!aMessage.json || aMessage.json.hudId != this.hudId) {
return;
}
switch (aMessage.name) {
case "WebConsole:Initialized":
this._onMessageManagerInitComplete();
break;
case "WebConsole:NetworkActivity":
this.handleNetworkActivity(aMessage.json);
break;
case "WebConsole:FileActivity":
this.outputMessage(CATEGORY_NETWORK, this.logFileActivity,
[aMessage.json.uri]);
break;
case "WebConsole:LocationChange":
this.owner.onLocationChange(aMessage.json);
break;
}
},
/**
* Callback method used to track the Web Console initialization via message
* manager.
*
* @private
*/
_onMessageManagerInitComplete: function WCF__onMessageManagerInitComplete()
{
this._messageManagerInitComplete = true;
if (this.proxy.connected) {
this._onInitComplete();
}
},
/**
* The event handler that is called whenever a user switches a filter on or
* off.
@ -1304,22 +1258,21 @@ WebConsoleFrame.prototype = {
},
/**
* Log network activity.
* Log network event.
*
* @param object aHttpActivity
* The HTTP activity to log.
* @param object aActorId
* The network event actor ID to log.
* @return nsIDOMElement|undefined
* The message element to display in the Web Console output.
*/
logNetActivity: function WCF_logNetActivity(aConnectionId)
logNetEvent: function WCF_logNetEvent(aActorId)
{
let networkInfo = this._networkRequests[aConnectionId];
let networkInfo = this._networkRequests[aActorId];
if (!networkInfo) {
return;
}
let entry = networkInfo.httpActivity.log.entries[0];
let request = entry.request;
let request = networkInfo.request;
let msgNode = this.document.createElementNS(XUL_NS, "hbox");
@ -1347,8 +1300,7 @@ WebConsoleFrame.prototype = {
let severity = SEVERITY_LOG;
let mixedRequest =
WebConsoleUtils.isMixedHTTPSRequest(request.url,
this.owner.contentLocation);
WebConsoleUtils.isMixedHTTPSRequest(request.url, this.contentLocation);
if (mixedRequest) {
urlNode.classList.add("webconsole-mixed-content");
this.makeMixedContentNode(linkNode);
@ -1369,18 +1321,18 @@ WebConsoleFrame.prototype = {
let messageNode = this.createMessageNode(CATEGORY_NETWORK, severity,
msgNode, null, null, clipboardText);
messageNode._connectionId = entry.connection;
messageNode._connectionId = aActorId;
messageNode.url = request.url;
this.makeOutputMessageLink(messageNode, function WCF_net_message_link() {
if (!messageNode._panelOpen) {
this.openNetworkPanel(messageNode, networkInfo.httpActivity);
this.openNetworkPanel(messageNode, networkInfo);
}
}.bind(this));
networkInfo.node = messageNode;
this._updateNetMessage(entry.connection);
this._updateNetMessage(aActorId);
return messageNode;
},
@ -1441,6 +1393,17 @@ WebConsoleFrame.prototype = {
return outputNode;
},
/**
* Handle the file activity messages coming from the remote Web Console.
*
* @param string aFileURI
* The file URI that was requested.
*/
handleFileActivity: function WCF_handleFileActivity(aFileURI)
{
this.outputMessage(CATEGORY_NETWORK, this.logFileActivity, [aFileURI]);
},
/**
* Inform user that the Web Console API has been replaced by a script
* in a content page.
@ -1453,86 +1416,122 @@ WebConsoleFrame.prototype = {
},
/**
* Handle the "WebConsole:NetworkActivity" message coming from the remote Web
* Console.
* Handle the network events coming from the remote Web Console.
*
* @param object aMessage
* The HTTP activity object. This object needs to hold two properties:
* - meta - some metadata about the request log:
* - stages - the stages the network request went through.
* - discardRequestBody and discardResponseBody - booleans that tell
* if the network request/response body was discarded or not.
* - log - the request and response information. This is a HAR-like
* object. See HUDService-content.js
* NetworkMonitor.createActivityObject().
* @param object aActor
* The NetworkEventActor grip.
*/
handleNetworkActivity: function WCF_handleNetworkActivity(aMessage)
handleNetworkEvent: function WCF_handleNetworkEvent(aActor)
{
let stage = aMessage.meta.stages[aMessage.meta.stages.length - 1];
let entry = aMessage.log.entries[0];
let networkInfo = {
node: null,
actor: aActor.actor,
discardRequestBody: true,
discardResponseBody: true,
startedDateTime: aActor.startedDateTime,
request: {
url: aActor.url,
method: aActor.method,
},
response: {},
timings: {},
updates: [], // track the list of network event updates
};
if (stage == "REQUEST_HEADER") {
let networkInfo = {
node: null,
httpActivity: aMessage,
};
this._networkRequests[aActor.actor] = networkInfo;
this.outputMessage(CATEGORY_NETWORK, this.logNetEvent, [aActor.actor]);
},
this._networkRequests[entry.connection] = networkInfo;
this.outputMessage(CATEGORY_NETWORK, this.logNetActivity,
[entry.connection]);
return;
}
else if (!(entry.connection in this._networkRequests)) {
/**
* Handle network event updates coming from the server.
*
* @param string aActorId
* The network event actor ID.
* @param string aType
* Update type.
* @param object aPacket
* Update details.
*/
handleNetworkEventUpdate:
function WCF_handleNetworkEventUpdate(aActorId, aType, aPacket)
{
let networkInfo = this._networkRequests[aActorId];
if (!networkInfo) {
return;
}
let networkInfo = this._networkRequests[entry.connection];
networkInfo.httpActivity = aMessage;
networkInfo.updates.push(aType);
switch (aType) {
case "requestHeaders":
networkInfo.request.headersSize = aPacket.headersSize;
break;
case "requestPostData":
networkInfo.discardRequestBody = aPacket.discardRequestBody;
networkInfo.request.bodySize = aPacket.dataSize;
break;
case "responseStart":
networkInfo.response.httpVersion = aPacket.response.httpVersion;
networkInfo.response.status = aPacket.response.status;
networkInfo.response.statusText = aPacket.response.statusText;
networkInfo.response.headersSize = aPacket.response.headersSize;
networkInfo.discardResponseBody = aPacket.response.discardResponseBody;
break;
case "responseContent":
networkInfo.response.content = {
mimeType: aPacket.mimeType,
};
networkInfo.response.bodySize = aPacket.contentSize;
networkInfo.discardResponseBody = aPacket.discardResponseBody;
break;
case "eventTimings":
networkInfo.totalTime = aPacket.totalTime;
break;
}
if (networkInfo.node) {
this._updateNetMessage(entry.connection);
this._updateNetMessage(aActorId);
}
// For unit tests we pass the HTTP activity object to the test callback,
// once requests complete.
if (this.owner.lastFinishedRequestCallback &&
aMessage.meta.stages.indexOf("REQUEST_STOP") > -1 &&
aMessage.meta.stages.indexOf("TRANSACTION_CLOSE") > -1) {
this.owner.lastFinishedRequestCallback(aMessage);
networkInfo.updates.indexOf("responseContent") > -1 &&
networkInfo.updates.indexOf("eventTimings") > -1) {
this.owner.lastFinishedRequestCallback(networkInfo, this);
}
},
/**
* Update an output message to reflect the latest state of a network request,
* given a network connection ID.
* given a network event actor ID.
*
* @private
* @param string aConnectionId
* The connection ID to update.
* @param string aActorId
* The network event actor ID for which you want to update the message.
*/
_updateNetMessage: function WCF__updateNetMessage(aConnectionId)
_updateNetMessage: function WCF__updateNetMessage(aActorId)
{
let networkInfo = this._networkRequests[aConnectionId];
let networkInfo = this._networkRequests[aActorId];
if (!networkInfo || !networkInfo.node) {
return;
}
let messageNode = networkInfo.node;
let httpActivity = networkInfo.httpActivity;
let stages = httpActivity.meta.stages;
let hasTransactionClose = stages.indexOf("TRANSACTION_CLOSE") > -1;
let hasResponseHeader = stages.indexOf("RESPONSE_HEADER") > -1;
let entry = httpActivity.log.entries[0];
let request = entry.request;
let response = entry.response;
let updates = networkInfo.updates;
let hasEventTimings = updates.indexOf("eventTimings") > -1;
let hasResponseStart = updates.indexOf("responseStart") > -1;
let request = networkInfo.request;
let response = networkInfo.response;
if (hasTransactionClose || hasResponseHeader) {
if (hasEventTimings || hasResponseStart) {
let status = [];
if (response.httpVersion && response.status) {
status = [response.httpVersion, response.status, response.statusText];
}
if (hasTransactionClose) {
status.push(l10n.getFormatStr("NetworkPanel.durationMS", [entry.time]));
if (hasEventTimings) {
status.push(l10n.getFormatStr("NetworkPanel.durationMS",
[networkInfo.totalTime]));
}
let statusText = "[" + status.join(" ") + "]";
@ -1543,7 +1542,7 @@ WebConsoleFrame.prototype = {
messageNode.clipboardText = [request.method, request.url, statusText]
.join(" ");
if (hasResponseHeader && response.status >= MIN_HTTP_ERROR_CODE &&
if (hasResponseStart && response.status >= MIN_HTTP_ERROR_CODE &&
response.status <= MAX_HTTP_ERROR_CODE) {
this.setMessageType(messageNode, CATEGORY_NETWORK, SEVERITY_ERROR);
}
@ -1567,27 +1566,138 @@ WebConsoleFrame.prototype = {
*/
openNetworkPanel: function WCF_openNetworkPanel(aNode, aHttpActivity)
{
let actor = aHttpActivity.actor;
if (actor) {
this.webConsoleClient.getRequestHeaders(actor, function(aResponse) {
if (aResponse.error) {
Cu.reportError("WCF_openNetworkPanel getRequestHeaders:" +
aResponse.error);
return;
}
aHttpActivity.request.headers = aResponse.headers;
this.webConsoleClient.getRequestCookies(actor, onRequestCookies);
}.bind(this));
}
let onRequestCookies = function(aResponse) {
if (aResponse.error) {
Cu.reportError("WCF_openNetworkPanel getRequestCookies:" +
aResponse.error);
return;
}
aHttpActivity.request.cookies = aResponse.cookies;
this.webConsoleClient.getResponseHeaders(actor, onResponseHeaders);
}.bind(this);
let onResponseHeaders = function(aResponse) {
if (aResponse.error) {
Cu.reportError("WCF_openNetworkPanel getResponseHeaders:" +
aResponse.error);
return;
}
aHttpActivity.response.headers = aResponse.headers;
this.webConsoleClient.getResponseCookies(actor, onResponseCookies);
}.bind(this);
let onResponseCookies = function(aResponse) {
if (aResponse.error) {
Cu.reportError("WCF_openNetworkPanel getResponseCookies:" +
aResponse.error);
return;
}
aHttpActivity.response.cookies = aResponse.cookies;
this.webConsoleClient.getRequestPostData(actor, onRequestPostData);
}.bind(this);
let onRequestPostData = function(aResponse) {
if (aResponse.error) {
Cu.reportError("WCF_openNetworkPanel getRequestPostData:" +
aResponse.error);
return;
}
aHttpActivity.request.postData = aResponse.postData;
aHttpActivity.discardRequestBody = aResponse.postDataDiscarded;
this.webConsoleClient.getResponseContent(actor, onResponseContent);
}.bind(this);
let onResponseContent = function(aResponse) {
if (aResponse.error) {
Cu.reportError("WCF_openNetworkPanel getResponseContent:" +
aResponse.error);
return;
}
aHttpActivity.response.content = aResponse.content;
aHttpActivity.discardResponseBody = aResponse.contentDiscarded;
this.webConsoleClient.getEventTimings(actor, onEventTimings);
}.bind(this);
let onEventTimings = function(aResponse) {
if (aResponse.error) {
Cu.reportError("WCF_openNetworkPanel getEventTimings:" +
aResponse.error);
return;
}
aHttpActivity.timings = aResponse.timings;
openPanel();
}.bind(this);
let openPanel = function() {
aNode._netPanel = netPanel;
let panel = netPanel.panel;
panel.openPopup(aNode, "after_pointer", 0, 0, false, false);
panel.sizeTo(450, 500);
panel.setAttribute("hudId", this.hudId);
panel.addEventListener("popuphiding", function WCF_netPanel_onHide() {
panel.removeEventListener("popuphiding", WCF_netPanel_onHide);
aNode._panelOpen = false;
aNode._netPanel = null;
});
aNode._panelOpen = true;
}.bind(this);
let netPanel = new NetworkPanel(this.popupset, aHttpActivity);
netPanel.linkNode = aNode;
aNode._netPanel = netPanel;
let panel = netPanel.panel;
panel.openPopup(aNode, "after_pointer", 0, 0, false, false);
panel.sizeTo(450, 500);
panel.setAttribute("hudId", aHttpActivity.hudId);
panel.addEventListener("popuphiding", function WCF_netPanel_onHide() {
panel.removeEventListener("popuphiding", WCF_netPanel_onHide);
aNode._panelOpen = false;
aNode._netPanel = null;
});
aNode._panelOpen = true;
if (!actor) {
openPanel();
}
return netPanel;
},
/**
* Handler for page location changes.
*
* @param string aURI
* New page location.
* @param string aTitle
* New page title.
*/
onLocationChange: function WCF_onLocationChange(aURI, aTitle)
{
this.contentLocation = aURI;
this.owner.onLocationChange(aURI, aTitle);
},
/**
* Output a message node. This filters a node appropriately, then sends it to
* the output, regrouping and pruning output as necessary.
@ -1847,7 +1957,7 @@ WebConsoleFrame.prototype = {
if (category == CATEGORY_NETWORK) {
let connectionId = null;
if (methodOrNode == this.logNetActivity) {
if (methodOrNode == this.logNetEvent) {
connectionId = args[0];
}
else if (typeof methodOrNode != "function") {
@ -1855,6 +1965,7 @@ WebConsoleFrame.prototype = {
}
if (connectionId && connectionId in this._networkRequests) {
delete this._networkRequests[connectionId];
this._releaseObject(connectionId);
}
}
else if (category == CATEGORY_WEBDEV &&
@ -1950,8 +2061,10 @@ WebConsoleFrame.prototype = {
}
delete this._cssNodes[desc + location];
}
else if (aNode.classList.contains("webconsole-msg-network")) {
else if (aNode._connectionId &&
aNode.classList.contains("webconsole-msg-network")) {
delete this._networkRequests[aNode._connectionId];
this._releaseObject(aNode._connectionId);
}
else if (aNode.classList.contains("webconsole-msg-inspector")) {
this.pruneConsoleDirNode(aNode);
@ -2424,11 +2537,11 @@ WebConsoleFrame.prototype = {
},
/**
* Release an object actor.
* Release an actor.
*
* @private
* @param string aActor
* The object actor ID you want to release.
* The actor ID you want to release.
*/
_releaseObject: function WCF__releaseObject(aActor)
{
@ -3701,6 +3814,10 @@ function WebConsoleConnectionProxy(aWebConsole)
this._onPageError = this._onPageError.bind(this);
this._onConsoleAPICall = this._onConsoleAPICall.bind(this);
this._onNetworkEvent = this._onNetworkEvent.bind(this);
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
this._onFileActivity = this._onFileActivity.bind(this);
this._onLocationChange = this._onLocationChange.bind(this);
}
WebConsoleConnectionProxy.prototype = {
@ -3766,13 +3883,19 @@ WebConsoleConnectionProxy.prototype = {
client.addListener("pageError", this._onPageError);
client.addListener("consoleAPICall", this._onConsoleAPICall);
client.addListener("networkEvent", this._onNetworkEvent);
client.addListener("networkEventUpdate", this._onNetworkEventUpdate);
client.addListener("fileActivity", this._onFileActivity);
client.addListener("locationChange", this._onLocationChange);
let listeners = ["PageError", "ConsoleAPI"];
let listeners = ["PageError", "ConsoleAPI", "NetworkActivity",
"FileActivity", "LocationChange"];
client.connect(function(aType, aTraits) {
client.listTabs(function(aResponse) {
let tab = aResponse.tabs[aResponse.selected];
this._consoleActor = tab.consoleActor;
this.owner.onLocationChange(tab.url, tab.title);
client.attachConsole(tab.consoleActor, listeners,
this._onAttachConsole.bind(this, aCallback));
}.bind(this));
@ -3870,6 +3993,80 @@ WebConsoleConnectionProxy.prototype = {
}
},
/**
* The "networkEvent" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string aType
* Message type.
* @param object aPacket
* The message received from the server.
*/
_onNetworkEvent: function WCCP__onNetworkEvent(aType, aPacket)
{
if (this.owner && aPacket.from == this._consoleActor) {
this.owner.handleNetworkEvent(aPacket.eventActor);
}
},
/**
* The "networkEventUpdate" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string aType
* Message type.
* @param object aPacket
* The message received from the server.
*/
_onNetworkEventUpdate: function WCCP__onNetworkEvenUpdatet(aType, aPacket)
{
if (this.owner) {
this.owner.handleNetworkEventUpdate(aPacket.from, aPacket.updateType,
aPacket);
}
},
/**
* The "fileActivity" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string aType
* Message type.
* @param object aPacket
* The message received from the server.
*/
_onFileActivity: function WCCP__onFileActivity(aType, aPacket)
{
if (this.owner && aPacket.from == this._consoleActor) {
this.owner.handleFileActivity(aPacket.uri);
}
},
/**
* The "locationChange" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string aType
* Message type.
* @param object aPacket
* The message received from the server.
*/
_onLocationChange: function WCCP__onLocationChange(aType, aPacket)
{
if (!this.owner || aPacket.from != this._consoleActor) {
return;
}
this.owner.onLocationChange(aPacket.uri, aPacket.title);
if (aPacket.state == "stop" && !aPacket.nativeConsoleAPI) {
this.owner.logWarningAboutReplacedAPI();
}
},
/**
* Release an object actor.
*
@ -3898,6 +4095,10 @@ WebConsoleConnectionProxy.prototype = {
this.client.removeListener("pageError", this._onPageError);
this.client.removeListener("consoleAPICall", this._onConsoleAPICall);
this.client.removeListener("networkEvent", this._onNetworkEvent);
this.client.removeListener("networkEventUpdate", this._onNetworkEventUpdate);
this.client.removeListener("fileActivity", this._onFileActivity);
this.client.removeListener("locationChange", this._onLocationChange);
this.client.close(aOnDisconnect);
this.client = null;

View File

@ -168,6 +168,10 @@ const ThreadStateTypes = {
*/
const UnsolicitedNotifications = {
"consoleAPICall": "consoleAPICall",
"fileActivity": "fileActivity",
"locationChange": "locationChange",
"networkEvent": "networkEvent",
"networkEventUpdate": "networkEventUpdate",
"newScript": "newScript",
"tabDetached": "tabDetached",
"tabNavigated": "tabNavigated",

View File

@ -99,8 +99,6 @@ var NetworkHelper =
return conv.ConvertToUnicode(aText);
}
catch (ex) {
Cu.reportError("NH_convertToUnicode(aText, '" +
aCharset + "') exception: " + ex);
return aText;
}
},
@ -177,8 +175,24 @@ var NetworkHelper =
readPostTextFromPage: function NH_readPostTextFromPage(aDocShell, aCharset)
{
let webNav = aDocShell.QueryInterface(Ci.nsIWebNavigation);
if (webNav instanceof Ci.nsIWebPageDescriptor) {
let descriptor = webNav.currentDescriptor;
return this.readPostTextFromPageViaWebNav(webNav, aCharset);
},
/**
* Reads the posted text from the page's cache, given an nsIWebNavigation
* object.
*
* @param nsIWebNavigation aWebNav
* @param string aCharset
* @returns string or null
* Returns the posted string if it was possible to read from
* aWebNav, otherwise null.
*/
readPostTextFromPageViaWebNav:
function NH_readPostTextFromPageViaWebNav(aWebNav, aCharset)
{
if (aWebNav instanceof Ci.nsIWebPageDescriptor) {
let descriptor = aWebNav.currentDescriptor;
if (descriptor instanceof Ci.nsISHEntry && descriptor.postData &&
descriptor instanceof Ci.nsISeekableStream) {

View File

@ -117,6 +117,143 @@ WebConsoleClient.prototype = {
this._client.request(packet);
},
/**
* 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)
{
let packet = {
to: this._actor,
type: "setPreferences",
preferences: aPreferences,
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the request headers from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getRequestHeaders: function WCC_getRequestHeaders(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getRequestHeaders",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the request cookies from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getRequestCookies: function WCC_getRequestCookies(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getRequestCookies",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the request post data from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getRequestPostData: function WCC_getRequestPostData(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getRequestPostData",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the response headers from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getResponseHeaders: function WCC_getResponseHeaders(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getResponseHeaders",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the response cookies from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getResponseCookies: function WCC_getResponseCookies(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getResponseCookies",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the response content from the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getResponseContent: function WCC_getResponseContent(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getResponseContent",
};
this._client.request(packet, aOnResponse);
},
/**
* Retrieve the timing information for the given NetworkEventActor.
*
* @param string aActor
* The NetworkEventActor ID.
* @param function aOnResponse
* The function invoked when the response is received.
*/
getEventTimings: function WCC_getEventTimings(aActor, aOnResponse)
{
let packet = {
to: aActor,
type: "getEventTimings",
};
this._client.request(packet, aOnResponse);
},
/**
* Start the given Web Console listeners.
*

File diff suppressed because it is too large Load Diff

View File

@ -24,12 +24,18 @@ XPCOMUtils.defineLazyModuleGetter(this, "PageErrorListener",
XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPIListener",
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ConsoleProgressListener",
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "JSTermHelpers",
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "JSPropertyProvider",
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetworkMonitor",
"resource://gre/modules/devtools/WebConsoleUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPIStorage",
"resource://gre/modules/ConsoleAPIStorage.jsm");
@ -51,6 +57,11 @@ function WebConsoleActor(aConnection, aTabActor)
this._objectActorsPool = new ActorPool(this.conn);
this.conn.addActorPool(this._objectActorsPool);
this._networkEventActorsPool = new ActorPool(this.conn);
this.conn.addActorPool(this._networkEventActorsPool);
this._prefs = {};
}
WebConsoleActor.prototype =
@ -67,10 +78,26 @@ WebConsoleActor.prototype =
* @private
* @type object
* @see ActorPool
* @see WebConsoleObjectActor
* @see this.objectGrip()
*/
_objectActorsPool: null,
/**
* Actor pool for all of the network event actors.
* @private
* @type object
* @see NetworkEventActor
*/
_networkEventActorsPool: null,
/**
* Web Console-related preferences.
* @private
* @type object
*/
_prefs: null,
/**
* Tells the current page location associated to the sandbox. When the page
* location is changed, we recreate the sandbox.
@ -108,6 +135,23 @@ WebConsoleActor.prototype =
*/
consoleAPIListener: null,
/**
* The NetworkMonitor instance.
*/
networkMonitor: null,
/**
* The ConsoleProgressListener instance.
*/
consoleProgressListener: null,
/**
* Getter for the NetworkMonitor.saveRequestAndResponseBodies preference.
* @type boolean
*/
get saveRequestAndResponseBodies()
this._prefs["NetworkMonitor.saveRequestAndResponseBodies"],
actorPrefix: "console",
grip: function WCA_grip()
@ -146,8 +190,18 @@ WebConsoleActor.prototype =
this.consoleAPIListener.destroy();
this.consoleAPIListener = null;
}
if (this.networkMonitor) {
this.networkMonitor.destroy();
this.networkMonitor = null;
}
if (this.consoleProgressListener) {
this.consoleProgressListener.destroy();
this.consoleProgressListener = null;
}
this.conn.removeActorPool(this._objectActorsPool);
this.conn.removeActorPool(this._networkEventActorsPool);
this._objectActorsPool = null;
this._networkEventActorsPool = null;
this._sandboxLocation = this.sandbox = null;
this.conn = this._browser = null;
},
@ -205,6 +259,21 @@ WebConsoleActor.prototype =
this._objectActorsPool.removeActor(aActor.actorID);
},
/**
* Release a network event actor.
*
* @param object aActor
* The NetworkEventActor instance you want to release.
*/
releaseNetworkEvent: function WCA_releaseNetworkEvent(aActor)
{
this._networkEventActorsPool.removeActor(aActor.actorID);
},
//////////////////
// Request handlers for known packet types.
//////////////////
/**
* Handler for the "startListeners" request.
*
@ -236,6 +305,30 @@ WebConsoleActor.prototype =
}
startedListeners.push(listener);
break;
case "NetworkActivity":
if (!this.networkMonitor) {
this.networkMonitor =
new NetworkMonitor(this.window, this);
this.networkMonitor.init();
}
startedListeners.push(listener);
break;
case "FileActivity":
if (!this.consoleProgressListener) {
this.consoleProgressListener =
new ConsoleProgressListener(this._browser, this);
}
this.consoleProgressListener.startMonitor(this.consoleProgressListener.
MONITOR_FILE_ACTIVITY);
startedListeners.push(listener);
break;
case "LocationChange":
if (!this.consoleProgressListener) {
this.consoleProgressListener =
new ConsoleProgressListener(this._browser, this);
}
this.consoleProgressListener.startMonitor(this.consoleProgressListener.
MONITOR_LOCATION_CHANGE);
}
}
return {
@ -259,7 +352,9 @@ WebConsoleActor.prototype =
// If no specific listeners are requested to be detached, we stop all
// listeners.
let toDetach = aRequest.listeners || ["PageError", "ConsoleAPI"];
let toDetach = aRequest.listeners ||
["PageError", "ConsoleAPI", "NetworkActivity",
"FileActivity", "LocationChange"];
while (toDetach.length > 0) {
let listener = toDetach.shift();
@ -278,6 +373,27 @@ WebConsoleActor.prototype =
}
stoppedListeners.push(listener);
break;
case "NetworkActivity":
if (this.networkMonitor) {
this.networkMonitor.destroy();
this.networkMonitor = null;
}
stoppedListeners.push(listener);
break;
case "FileActivity":
if (this.consoleProgressListener) {
this.consoleProgressListener.stopMonitor(this.consoleProgressListener.
MONITOR_FILE_ACTIVITY);
}
stoppedListeners.push(listener);
break;
case "LocationChange":
if (this.consoleProgressListener) {
this.consoleProgressListener.stopMonitor(this.consoleProgressListener.
MONITOR_LOCATION_CHANGE);
}
stoppedListeners.push(listener);
break;
}
}
@ -409,6 +525,24 @@ WebConsoleActor.prototype =
return {};
},
/**
* 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) {
this._prefs[key] = aRequest.preferences[key];
}
return { updated: Object.keys(aRequest.preferences) };
},
//////////////////
// End of request handlers.
//////////////////
/**
* Create the JavaScript sandbox where user input is evaluated.
* @private
@ -474,6 +608,10 @@ WebConsoleActor.prototype =
return result;
},
//////////////////
// Event handlers for various listeners.
//////////////////
/**
* Handler for page errors received from the PageErrorListener. This method
* sends the nsIScriptError to the remote Web Console client.
@ -521,6 +659,7 @@ WebConsoleActor.prototype =
* Handler for window.console API calls received from the ConsoleAPIListener.
* This method sends the object to the remote Web Console client.
*
* @see ConsoleAPIListener
* @param object aMessage
* The console API call we need to send to the remote client.
*/
@ -534,6 +673,88 @@ WebConsoleActor.prototype =
this.conn.send(packet);
},
/**
* Handler for network events. This method is invoked when a new network event
* is about to be recorded.
*
* @see NetworkEventActor
* @see NetworkMonitor from WebConsoleUtils.jsm
*
* @param object aEvent
* The initial network request event information.
* @return object
* A new NetworkEventActor is returned. This is used for tracking the
* network request and response.
*/
onNetworkEvent: function WCA_onNetworkEvent(aEvent)
{
let actor = new NetworkEventActor(aEvent, this);
this._networkEventActorsPool.addActor(actor);
let packet = {
from: this.actorID,
type: "networkEvent",
eventActor: actor.grip(),
};
this.conn.send(packet);
return actor;
},
/**
* Handler for file activity. This method sends the file request information
* to the remote Web Console client.
*
* @see ConsoleProgressListener
* @param string aFileURI
* The requested file URI.
*/
onFileActivity: function WCA_onFileActivity(aFileURI)
{
let packet = {
from: this.actorID,
type: "fileActivity",
uri: aFileURI,
};
this.conn.send(packet);
},
/**
* Handler for location changes. This method sends the new browser location
* to the remote Web Console client.
*
* @see ConsoleProgressListener
* @param string aState
* Tells the location change state:
* - "start" means a load has begun.
* - "stop" means load completed.
* @param string aURI
* The new browser URI.
* @param string aTitle
* The new page title URI.
*/
onLocationChange: function WCA_onLocationChange(aState, aURI, aTitle)
{
// TODO: we should use tabNavigated, but that lives on the TabActor and in
// the Web Console we do not attach to the TabActor. Plus, the tabNavigated
// packet is only sent at the end of a page load - for the Web Console we
// need it as early as possible. Follow-up bug material?
let packet = {
from: this.actorID,
type: "locationChange",
uri: aURI,
title: aTitle,
state: aState,
nativeConsoleAPI: this.hasNativeConsoleAPI(),
};
this.conn.send(packet);
},
//////////////////
// End of event handlers for various listeners.
//////////////////
/**
* Prepare a message from the console API to be sent to the remote Web Console
* instance.
@ -604,6 +825,7 @@ WebConsoleActor.prototype.requestTypes =
evaluateJS: WebConsoleActor.prototype.onEvaluateJS,
autocomplete: WebConsoleActor.prototype.onAutocomplete,
clearMessagesCache: WebConsoleActor.prototype.onClearMessagesCache,
setPreferences: WebConsoleActor.prototype.onSetPreferences,
};
/**
@ -678,3 +900,375 @@ WebConsoleObjectActor.prototype.requestTypes =
"release": WebConsoleObjectActor.prototype.onRelease,
};
/**
* Creates an actor for a network event.
*
* @constructor
* @param object aNetworkEvent
* The network event you want to use the actor for.
* @param object aWebConsoleActor
* The parent WebConsoleActor instance for this object.
*/
function NetworkEventActor(aNetworkEvent, aWebConsoleActor)
{
this.parent = aWebConsoleActor;
this.conn = this.parent.conn;
this._startedDateTime = aNetworkEvent.startedDateTime;
this._request = {
method: aNetworkEvent.method,
url: aNetworkEvent.url,
httpVersion: aNetworkEvent.httpVersion,
headers: [],
cookies: [],
headersSize: aNetworkEvent.headersSize,
postData: {},
};
this._response = {
headers: [],
cookies: [],
content: {},
};
this._timings = {};
this._discardRequestBody = aNetworkEvent.discardRequestBody;
this._discardResponseBody = aNetworkEvent.discardResponseBody;
}
NetworkEventActor.prototype =
{
_request: null,
_response: null,
_timings: null,
actorPrefix: "netEvent",
/**
* Returns a grip for this actor for returning in a protocol message.
*/
grip: function NEA_grip()
{
return {
actor: this.actorID,
startedDateTime: this._startedDateTime,
url: this._request.url,
method: this._request.method,
};
},
/**
* Releases this actor from the pool.
*/
release: function NEA_release()
{
this.parent.releaseNetworkEvent(this);
},
/**
* Handle a protocol request to release a grip.
*/
onRelease: function NEA_onRelease()
{
this.release();
return {};
},
/**
* The "getRequestHeaders" packet type handler.
*
* @return object
* The response packet - network request headers.
*/
onGetRequestHeaders: function NEA_onGetRequestHeaders()
{
return {
from: this.actorID,
headers: this._request.headers,
headersSize: this._request.headersSize,
};
},
/**
* The "getRequestCookies" packet type handler.
*
* @return object
* The response packet - network request cookies.
*/
onGetRequestCookies: function NEA_onGetRequestCookies()
{
return {
from: this.actorID,
cookies: this._request.cookies,
};
},
/**
* The "getRequestPostData" packet type handler.
*
* @return object
* The response packet - network POST data.
*/
onGetRequestPostData: function NEA_onGetRequestPostData()
{
return {
from: this.actorID,
postData: this._request.postData,
postDataDiscarded: this._discardRequestBody,
};
},
/**
* The "getResponseHeaders" packet type handler.
*
* @return object
* The response packet - network response headers.
*/
onGetResponseHeaders: function NEA_onGetResponseHeaders()
{
return {
from: this.actorID,
headers: this._response.headers,
headersSize: this._response.headersSize,
};
},
/**
* The "getResponseCookies" packet type handler.
*
* @return object
* The response packet - network response cookies.
*/
onGetResponseCookies: function NEA_onGetResponseCookies()
{
return {
from: this.actorID,
cookies: this._response.cookies,
};
},
/**
* The "getResponseContent" packet type handler.
*
* @return object
* The response packet - network response content.
*/
onGetResponseContent: function NEA_onGetResponseContent()
{
return {
from: this.actorID,
content: this._response.content,
contentDiscarded: this._discardResponseBody,
};
},
/**
* The "getEventTimings" packet type handler.
*
* @return object
* The response packet - network event timings.
*/
onGetEventTimings: function NEA_onGetEventTimings()
{
return {
from: this.actorID,
timings: this._timings,
totalTime: this._totalTime,
};
},
/******************************************************************
* Listeners for new network event data coming from NetworkMonitor.
******************************************************************/
/**
* Add network request headers.
*
* @param array aHeaders
* The request headers array.
*/
addRequestHeaders: function NEA_addRequestHeaders(aHeaders)
{
this._request.headers = aHeaders;
let packet = {
from: this.actorID,
type: "networkEventUpdate",
updateType: "requestHeaders",
headers: aHeaders.length,
headersSize: this._request.headersSize,
};
this.conn.send(packet);
},
/**
* Add network request cookies.
*
* @param array aCookies
* The request cookies array.
*/
addRequestCookies: function NEA_addRequestCookies(aCookies)
{
this._request.cookies = aCookies;
let packet = {
from: this.actorID,
type: "networkEventUpdate",
updateType: "requestCookies",
cookies: aCookies.length,
};
this.conn.send(packet);
},
/**
* Add network request POST data.
*
* @param object aPostData
* The request POST data.
*/
addRequestPostData: function NEA_addRequestPostData(aPostData)
{
this._request.postData = aPostData;
let packet = {
from: this.actorID,
type: "networkEventUpdate",
updateType: "requestPostData",
dataSize: aPostData.text.length,
discardRequestBody: this._discardRequestBody,
};
this.conn.send(packet);
},
/**
* Add the initial network response information.
*
* @param object aInfo
* The response information.
*/
addResponseStart: function NEA_addResponseStart(aInfo)
{
this._response.httpVersion = aInfo.httpVersion;
this._response.status = aInfo.status;
this._response.statusText = aInfo.statusText;
this._response.headersSize = aInfo.headersSize;
this._discardResponseBody = aInfo.discardResponseBody;
let packet = {
from: this.actorID,
type: "networkEventUpdate",
updateType: "responseStart",
response: aInfo,
};
this.conn.send(packet);
},
/**
* Add network response headers.
*
* @param array aHeaders
* The response headers array.
*/
addResponseHeaders: function NEA_addResponseHeaders(aHeaders)
{
this._response.headers = aHeaders;
let packet = {
from: this.actorID,
type: "networkEventUpdate",
updateType: "responseHeaders",
headers: aHeaders.length,
headersSize: this._response.headersSize,
};
this.conn.send(packet);
},
/**
* Add network response cookies.
*
* @param array aCookies
* The response cookies array.
*/
addResponseCookies: function NEA_addResponseCookies(aCookies)
{
this._response.cookies = aCookies;
let packet = {
from: this.actorID,
type: "networkEventUpdate",
updateType: "responseCookies",
cookies: aCookies.length,
};
this.conn.send(packet);
},
/**
* Add network response content.
*
* @param object aContent
* The response content.
* @param boolean aDiscardedResponseBody
* Tells if the response content was recorded or not.
*/
addResponseContent:
function NEA_addResponseContent(aContent, aDiscardedResponseBody)
{
this._response.content = aContent;
let packet = {
from: this.actorID,
type: "networkEventUpdate",
updateType: "responseContent",
mimeType: aContent.mimeType,
contentSize: aContent.text.length,
discardResponseBody: aDiscardedResponseBody,
};
this.conn.send(packet);
},
/**
* Add network event timing information.
*
* @param number aTotal
* The total time of the network event.
* @param object aTimings
* Timing details about the network event.
*/
addEventTimings: function NEA_addEventTimings(aTotal, aTimings)
{
this._totalTime = aTotal;
this._timings = aTimings;
let packet = {
from: this.actorID,
type: "networkEventUpdate",
updateType: "eventTimings",
totalTime: aTotal,
};
this.conn.send(packet);
},
};
NetworkEventActor.prototype.requestTypes =
{
"release": NetworkEventActor.prototype.onRelease,
"getRequestHeaders": NetworkEventActor.prototype.onGetRequestHeaders,
"getRequestCookies": NetworkEventActor.prototype.onGetRequestCookies,
"getRequestPostData": NetworkEventActor.prototype.onGetRequestPostData,
"getResponseHeaders": NetworkEventActor.prototype.onGetResponseHeaders,
"getResponseCookies": NetworkEventActor.prototype.onGetResponseCookies,
"getResponseContent": NetworkEventActor.prototype.onGetResponseContent,
"getEventTimings": NetworkEventActor.prototype.onGetEventTimings,
};