mirror of
https://github.com/roytam1/palemoon26.git
synced 2026-05-27 21:48:27 +00:00
c2e084c761
bug654550, bug533840, bug884654, bug692829, bug855504, bug884750, bug877320, bug879520, bug731311, bug861478, bug886375, bug835885, bug882416, bug648949, bug885281, bug885030, bug887165, bug887167, bug885183, bug875244
573 lines
17 KiB
JavaScript
573 lines
17 KiB
JavaScript
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
"use strict";
|
|
|
|
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
|
|
Cu.import("resource:///modules/source-editor.jsm");
|
|
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
|
Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
|
|
Cu.import("resource:///modules/devtools/VariablesView.jsm");
|
|
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
|
"resource://gre/modules/PluralForm.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
|
|
"resource://gre/modules/devtools/NetworkHelper.jsm");
|
|
|
|
const NET_STRINGS_URI = "chrome://browser/locale/devtools/netmonitor.properties";
|
|
const LISTENERS = [ "NetworkActivity" ];
|
|
const NET_PREFS = { "NetworkMonitor.saveRequestAndResponseBodies": true };
|
|
|
|
/**
|
|
* Object defining the network monitor controller components.
|
|
*/
|
|
let NetMonitorController = {
|
|
/**
|
|
* Initializes the view.
|
|
*
|
|
* @return object
|
|
* A promise that is resolved when the monitor finishes startup.
|
|
*/
|
|
startupNetMonitor: function() {
|
|
if (this._isInitialized) {
|
|
return this._startup.promise;
|
|
}
|
|
this._isInitialized = true;
|
|
|
|
let deferred = this._startup = promise.defer();
|
|
|
|
NetMonitorView.initialize(() => {
|
|
NetMonitorView._isInitialized = true;
|
|
deferred.resolve();
|
|
});
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
/**
|
|
* Destroys the view and disconnects the monitor client from the server.
|
|
*
|
|
* @return object
|
|
* A promise that is resolved when the monitor finishes shutdown.
|
|
*/
|
|
shutdownNetMonitor: function() {
|
|
if (this._isDestroyed) {
|
|
return this._shutdown.promise;
|
|
}
|
|
this._isDestroyed = true;
|
|
this._startup = null;
|
|
|
|
let deferred = this._shutdown = promise.defer();
|
|
|
|
NetMonitorView.destroy(() => {
|
|
NetMonitorView._isDestroyed = true;
|
|
this.TargetEventsHandler.disconnect();
|
|
this.NetworkEventsHandler.disconnect();
|
|
|
|
this.disconnect();
|
|
deferred.resolve();
|
|
});
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
/**
|
|
* Initiates remote or chrome network monitoring based on the current target,
|
|
* wiring event handlers as necessary.
|
|
*
|
|
* @return object
|
|
* A promise that is resolved when the monitor finishes connecting.
|
|
*/
|
|
connect: function() {
|
|
if (this._connection) {
|
|
return this._connection.promise;
|
|
}
|
|
|
|
let deferred = this._connection = promise.defer();
|
|
|
|
let target = this._target;
|
|
let { client, form } = target;
|
|
if (target.chrome) {
|
|
this._startChromeMonitoring(client, form.consoleActor, deferred.resolve);
|
|
} else {
|
|
this._startMonitoringTab(client, form, deferred.resolve);
|
|
}
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
/**
|
|
* Disconnects the debugger client and removes event handlers as necessary.
|
|
*/
|
|
disconnect: function() {
|
|
// When debugging local or a remote instance, the connection is closed by
|
|
// the RemoteTarget.
|
|
this._connection = null;
|
|
this.client = null;
|
|
this.tabClient = null;
|
|
this.webConsoleClient = null;
|
|
},
|
|
|
|
/**
|
|
* Sets up a monitoring session.
|
|
*
|
|
* @param DebuggerClient aClient
|
|
* The debugger client.
|
|
* @param object aTabGrip
|
|
* The remote protocol grip of the tab.
|
|
* @param function aCallback
|
|
* A function to invoke once the client attached to the console client.
|
|
*/
|
|
_startMonitoringTab: function(aClient, aTabGrip, aCallback) {
|
|
if (!aClient) {
|
|
Cu.reportError("No client found!");
|
|
return;
|
|
}
|
|
this.client = aClient;
|
|
|
|
aClient.attachTab(aTabGrip.actor, (aResponse, aTabClient) => {
|
|
if (!aTabClient) {
|
|
Cu.reportError("No tab client found!");
|
|
return;
|
|
}
|
|
this.tabClient = aTabClient;
|
|
|
|
aClient.attachConsole(aTabGrip.consoleActor, LISTENERS, (aResponse, aWebConsoleClient) => {
|
|
if (!aWebConsoleClient) {
|
|
Cu.reportError("Couldn't attach to console: " + aResponse.error);
|
|
return;
|
|
}
|
|
this.webConsoleClient = aWebConsoleClient;
|
|
this.webConsoleClient.setPreferences(NET_PREFS, () => {
|
|
this.TargetEventsHandler.connect();
|
|
this.NetworkEventsHandler.connect();
|
|
|
|
if (aCallback) {
|
|
aCallback();
|
|
}
|
|
});
|
|
});
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Sets up a chrome monitoring session.
|
|
*
|
|
* @param DebuggerClient aClient
|
|
* The debugger client.
|
|
* @param object aConsoleActor
|
|
* The remote protocol grip of the chrome debugger.
|
|
* @param function aCallback
|
|
* A function to invoke once the client attached to the console client.
|
|
*/
|
|
_startChromeMonitoring: function(aClient, aConsoleActor, aCallback) {
|
|
if (!aClient) {
|
|
Cu.reportError("No client found!");
|
|
return;
|
|
}
|
|
this.client = aClient;
|
|
|
|
aClient.attachConsole(aConsoleActor, LISTENERS, (aResponse, aWebConsoleClient) => {
|
|
if (!aWebConsoleClient) {
|
|
Cu.reportError("Couldn't attach to console: " + aResponse.error);
|
|
return;
|
|
}
|
|
this.webConsoleClient = aWebConsoleClient;
|
|
this.webConsoleClient.setPreferences(NET_PREFS, () => {
|
|
this.TargetEventsHandler.connect();
|
|
this.NetworkEventsHandler.connect();
|
|
|
|
if (aCallback) {
|
|
aCallback();
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
_isInitialized: false,
|
|
_isDestroyed: false,
|
|
_startup: null,
|
|
_shutdown: null,
|
|
_connection: null,
|
|
client: null,
|
|
tabClient: null,
|
|
webConsoleClient: null
|
|
};
|
|
|
|
/**
|
|
* Functions handling target-related lifetime events.
|
|
*/
|
|
function TargetEventsHandler() {
|
|
this._onTabNavigated = this._onTabNavigated.bind(this);
|
|
this._onTabDetached = this._onTabDetached.bind(this);
|
|
}
|
|
|
|
TargetEventsHandler.prototype = {
|
|
get target() NetMonitorController._target,
|
|
get webConsoleClient() NetMonitorController.webConsoleClient,
|
|
|
|
/**
|
|
* Listen for events emitted by the current tab target.
|
|
*/
|
|
connect: function() {
|
|
dumpn("TargetEventsHandler is connecting...");
|
|
this.target.on("close", this._onTabDetached);
|
|
this.target.on("navigate", this._onTabNavigated);
|
|
this.target.on("will-navigate", this._onTabNavigated);
|
|
},
|
|
|
|
/**
|
|
* Remove events emitted by the current tab target.
|
|
*/
|
|
disconnect: function() {
|
|
if (!this.target) {
|
|
return;
|
|
}
|
|
dumpn("TargetEventsHandler is disconnecting...");
|
|
this.target.off("close", this._onTabDetached);
|
|
this.target.off("navigate", this._onTabNavigated);
|
|
this.target.off("will-navigate", this._onTabNavigated);
|
|
},
|
|
|
|
/**
|
|
* Called for each location change in the monitored tab.
|
|
*
|
|
* @param string aType
|
|
* Packet type.
|
|
* @param object aPacket
|
|
* Packet received from the server.
|
|
*/
|
|
_onTabNavigated: function(aType, aPacket) {
|
|
switch (aType) {
|
|
case "will-navigate": {
|
|
// Reset UI.
|
|
NetMonitorView.RequestsMenu.reset();
|
|
NetMonitorView.Sidebar.reset();
|
|
NetMonitorView.NetworkDetails.reset();
|
|
|
|
// Reset global helpers cache.
|
|
nsIURL.store.clear();
|
|
drain.store.clear();
|
|
|
|
window.emit("NetMonitor:TargetWillNavigate");
|
|
break;
|
|
}
|
|
case "navigate": {
|
|
window.emit("NetMonitor:TargetNavigate");
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Called when the monitored tab is closed.
|
|
*/
|
|
_onTabDetached: function() {
|
|
NetMonitorController.shutdownNetMonitor();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Functions handling target network events.
|
|
*/
|
|
function NetworkEventsHandler() {
|
|
this._onNetworkEvent = this._onNetworkEvent.bind(this);
|
|
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
|
|
this._onRequestHeaders = this._onRequestHeaders.bind(this);
|
|
this._onRequestCookies = this._onRequestCookies.bind(this);
|
|
this._onRequestPostData = this._onRequestPostData.bind(this);
|
|
this._onResponseHeaders = this._onResponseHeaders.bind(this);
|
|
this._onResponseCookies = this._onResponseCookies.bind(this);
|
|
this._onResponseContent = this._onResponseContent.bind(this);
|
|
this._onEventTimings = this._onEventTimings.bind(this);
|
|
}
|
|
|
|
NetworkEventsHandler.prototype = {
|
|
get client() NetMonitorController._target.client,
|
|
get webConsoleClient() NetMonitorController.webConsoleClient,
|
|
|
|
/**
|
|
* Connect to the current target client.
|
|
*/
|
|
connect: function() {
|
|
dumpn("NetworkEventsHandler is connecting...");
|
|
this.client.addListener("networkEvent", this._onNetworkEvent);
|
|
this.client.addListener("networkEventUpdate", this._onNetworkEventUpdate);
|
|
},
|
|
|
|
/**
|
|
* Disconnect from the client.
|
|
*/
|
|
disconnect: function() {
|
|
if (!this.client) {
|
|
return;
|
|
}
|
|
dumpn("NetworkEventsHandler is disconnecting...");
|
|
this.client.removeListener("networkEvent", this._onNetworkEvent);
|
|
this.client.removeListener("networkEventUpdate", this._onNetworkEventUpdate);
|
|
},
|
|
|
|
/**
|
|
* The "networkEvent" message type handler.
|
|
*
|
|
* @param string aType
|
|
* Message type.
|
|
* @param object aPacket
|
|
* The message received from the server.
|
|
*/
|
|
_onNetworkEvent: function(aType, aPacket) {
|
|
let { actor, startedDateTime, method, url, isXHR } = aPacket.eventActor;
|
|
NetMonitorView.RequestsMenu.addRequest(actor, startedDateTime, method, url, isXHR);
|
|
|
|
window.emit("NetMonitor:NetworkEvent");
|
|
},
|
|
|
|
/**
|
|
* The "networkEventUpdate" message type handler.
|
|
*
|
|
* @param string aType
|
|
* Message type.
|
|
* @param object aPacket
|
|
* The message received from the server.
|
|
*/
|
|
_onNetworkEventUpdate: function(aType, aPacket) {
|
|
let actor = aPacket.from;
|
|
|
|
switch (aPacket.updateType) {
|
|
case "requestHeaders":
|
|
this.webConsoleClient.getRequestHeaders(actor, this._onRequestHeaders);
|
|
window.emit("NetMonitor:NetworkEventUpdating:RequestHeaders");
|
|
break;
|
|
case "requestCookies":
|
|
this.webConsoleClient.getRequestCookies(actor, this._onRequestCookies);
|
|
window.emit("NetMonitor:NetworkEventUpdating:RequestCookies");
|
|
break;
|
|
case "requestPostData":
|
|
this.webConsoleClient.getRequestPostData(actor, this._onRequestPostData);
|
|
window.emit("NetMonitor:NetworkEventUpdating:RequestPostData");
|
|
break;
|
|
case "responseHeaders":
|
|
this.webConsoleClient.getResponseHeaders(actor, this._onResponseHeaders);
|
|
window.emit("NetMonitor:NetworkEventUpdating:ResponseHeaders");
|
|
break;
|
|
case "responseCookies":
|
|
this.webConsoleClient.getResponseCookies(actor, this._onResponseCookies);
|
|
window.emit("NetMonitor:NetworkEventUpdating:ResponseCookies");
|
|
break;
|
|
case "responseStart":
|
|
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
|
|
httpVersion: aPacket.response.httpVersion,
|
|
status: aPacket.response.status,
|
|
statusText: aPacket.response.statusText,
|
|
headersSize: aPacket.response.headersSize
|
|
});
|
|
window.emit("NetMonitor:NetworkEventUpdating:ResponseStart");
|
|
break;
|
|
case "responseContent":
|
|
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
|
|
contentSize: aPacket.contentSize,
|
|
mimeType: aPacket.mimeType
|
|
});
|
|
this.webConsoleClient.getResponseContent(actor, this._onResponseContent);
|
|
window.emit("NetMonitor:NetworkEventUpdating:ResponseContent");
|
|
break;
|
|
case "eventTimings":
|
|
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
|
|
totalTime: aPacket.totalTime
|
|
});
|
|
this.webConsoleClient.getEventTimings(actor, this._onEventTimings);
|
|
window.emit("NetMonitor:NetworkEventUpdating:EventTimings");
|
|
break;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Handles additional information received for a "requestHeaders" packet.
|
|
*
|
|
* @param object aResponse
|
|
* The message received from the server.
|
|
*/
|
|
_onRequestHeaders: function(aResponse) {
|
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
|
requestHeaders: aResponse
|
|
});
|
|
window.emit("NetMonitor:NetworkEventUpdated:RequestHeaders");
|
|
},
|
|
|
|
/**
|
|
* Handles additional information received for a "requestCookies" packet.
|
|
*
|
|
* @param object aResponse
|
|
* The message received from the server.
|
|
*/
|
|
_onRequestCookies: function(aResponse) {
|
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
|
requestCookies: aResponse
|
|
});
|
|
window.emit("NetMonitor:NetworkEventUpdated:RequestCookies");
|
|
},
|
|
|
|
/**
|
|
* Handles additional information received for a "requestPostData" packet.
|
|
*
|
|
* @param object aResponse
|
|
* The message received from the server.
|
|
*/
|
|
_onRequestPostData: function(aResponse) {
|
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
|
requestPostData: aResponse
|
|
});
|
|
window.emit("NetMonitor:NetworkEventUpdated:RequestPostData");
|
|
},
|
|
|
|
/**
|
|
* Handles additional information received for a "responseHeaders" packet.
|
|
*
|
|
* @param object aResponse
|
|
* The message received from the server.
|
|
*/
|
|
_onResponseHeaders: function(aResponse) {
|
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
|
responseHeaders: aResponse
|
|
});
|
|
window.emit("NetMonitor:NetworkEventUpdated:ResponseHeaders");
|
|
},
|
|
|
|
/**
|
|
* Handles additional information received for a "responseCookies" packet.
|
|
*
|
|
* @param object aResponse
|
|
* The message received from the server.
|
|
*/
|
|
_onResponseCookies: function(aResponse) {
|
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
|
responseCookies: aResponse
|
|
});
|
|
window.emit("NetMonitor:NetworkEventUpdated:ResponseCookies");
|
|
},
|
|
|
|
/**
|
|
* Handles additional information received for a "responseContent" packet.
|
|
*
|
|
* @param object aResponse
|
|
* The message received from the server.
|
|
*/
|
|
_onResponseContent: function(aResponse) {
|
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
|
responseContent: aResponse
|
|
});
|
|
window.emit("NetMonitor:NetworkEventUpdated:ResponseContent");
|
|
},
|
|
|
|
/**
|
|
* Handles additional information received for a "eventTimings" packet.
|
|
*
|
|
* @param object aResponse
|
|
* The message received from the server.
|
|
*/
|
|
_onEventTimings: function(aResponse) {
|
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
|
eventTimings: aResponse
|
|
});
|
|
window.emit("NetMonitor:NetworkEventUpdated:EventTimings");
|
|
},
|
|
|
|
/**
|
|
* Fetches the full text of a LongString.
|
|
*
|
|
* @param object | string aStringGrip
|
|
* The long string grip containing the corresponding actor.
|
|
* If you pass in a plain string (by accident or because you're lazy),
|
|
* then a promise of the same string is simply returned.
|
|
* @return object Promise
|
|
* A promise that is resolved when the full string contents
|
|
* are available, or rejected if something goes wrong.
|
|
*/
|
|
getString: function(aStringGrip) {
|
|
// Make sure this is a long string.
|
|
if (typeof aStringGrip != "object" || aStringGrip.type != "longString") {
|
|
return promise.resolve(aStringGrip); // Go home string, you're drunk.
|
|
}
|
|
// Fetch the long string only once.
|
|
if (aStringGrip._fullText) {
|
|
return aStringGrip._fullText.promise;
|
|
}
|
|
|
|
let deferred = aStringGrip._fullText = promise.defer();
|
|
let { actor, initial, length } = aStringGrip;
|
|
let longStringClient = this.webConsoleClient.longString(aStringGrip);
|
|
|
|
longStringClient.substring(initial.length, length, (aResponse) => {
|
|
if (aResponse.error) {
|
|
Cu.reportError(aResponse.error + ": " + aResponse.message);
|
|
deferred.reject(aResponse);
|
|
return;
|
|
}
|
|
deferred.resolve(initial + aResponse.substring);
|
|
});
|
|
|
|
return deferred.promise;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Localization convenience methods.
|
|
*/
|
|
let L10N = new ViewHelpers.L10N(NET_STRINGS_URI);
|
|
|
|
/**
|
|
* Shortcuts for accessing various network monitor preferences.
|
|
*/
|
|
let Prefs = new ViewHelpers.Prefs("devtools.netmonitor", {
|
|
networkDetailsWidth: ["Int", "panes-network-details-width"],
|
|
networkDetailsHeight: ["Int", "panes-network-details-height"]
|
|
});
|
|
|
|
/**
|
|
* Returns true if this is document is in RTL mode.
|
|
* @return boolean
|
|
*/
|
|
XPCOMUtils.defineLazyGetter(window, "isRTL", function() {
|
|
return window.getComputedStyle(document.documentElement, null).direction == "rtl";
|
|
});
|
|
|
|
/**
|
|
* Convenient way of emitting events from the panel window.
|
|
*/
|
|
EventEmitter.decorate(this);
|
|
|
|
/**
|
|
* Preliminary setup for the NetMonitorController object.
|
|
*/
|
|
NetMonitorController.TargetEventsHandler = new TargetEventsHandler();
|
|
NetMonitorController.NetworkEventsHandler = new NetworkEventsHandler();
|
|
|
|
/**
|
|
* Export some properties to the global scope for easier access.
|
|
*/
|
|
Object.defineProperties(window, {
|
|
"gNetwork": {
|
|
get: function() NetMonitorController.NetworkEventsHandler
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Helper method for debugging.
|
|
* @param string
|
|
*/
|
|
function dumpn(str) {
|
|
if (wantLogging) {
|
|
dump("NET-FRONTEND: " + str + "\n");
|
|
}
|
|
}
|
|
|
|
let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|