mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:37:11 +00:00
a7bc0406ee
- Bug 1155006: Fix unified build sensitivities in js/src/jit. r=shu (6e24e1af1) - Bug 1162766 - Fix more bad implicit constructors in js. r=evilpie (39961b06d) - Bug 1151606 - Stream atoms instead of raw pointers for native functions in tracked optimizations. (r=djvj) (7641ee9d6) - pointer style (540728104) - Bug 1154997 - Deal with self-hosted builtins when stringifying tracked optimization type info. (r=djvj) (92f9a54e6) - pointer style (45742d820) - Bug 1154115 - Rewrite the JSAPI profiling API to use a FrameHandle, as to avoid multiple lookups in JitcodeGlobalTable. (r=djvj) (4d202ba9e) - Bug 1119023 - Timeline in new perf tool should filter out markers, r=jsantell (6fc1a8bbe) - Bug 1132755 - Allocations tree has a bunch of columns that don't make sense, r=jsantell (1ae9ee7e2) - Bug 1142744 - Fix tests broken by bug 1132755, r=me (cc495f72d) - Bug 1133058 - OptionsView button, when clicked, should have an 'open' attribute. r=vp (65a78d896) - Bug 1132765 - Pass through performance memory options for 'probability' and 'maxLogLength' from the front to the memory actor. r=vp (f9bbbe098) - Bug 1141817 - Fix yield statement to correctly return memory actor state so that the performance tool can poll for allocations during recording. r=vp (2ddf7d528) - Bug 1141817 - Followup to fix additional intermittents like bug 1132370, r=vp (eab962f01) - Bug 1142748 - Use a single configuration for starting/stopping recordings, r=jsantell (0181b319a) - bit of Bug 879008 - New UI for the sampling Profiler (32c4d0fe8) - Bug 1123815 - Merge gum into fx-team to enable the Performance++ tool, r=me (84aabbd61) - Bug 1143933 - Expose raw JIT optimization information in performance front end. r=vp,shu (f68a6df50) - Bug 1143915 - Allow multiple calls to memory and timeline actor's start methods, to return the local start time from the actor. r=vp (028ac4187) - Bug 978948 - Add animation generator support for setTimeout in the canvas debugger. r=vp (42d623452) - Bug 985488 - Allow canvas debugger to time out and stop recording frames. Canvas debugger 'wait' style now matches other media styles. Update labels in canvas debugger to explicitly state that it's waiting for rAF cycles, rather than appearing as if something went wrong. r=vporof (b4670d843) - Bug 1144163 - Add a rulers highlighter; added unit test. r=pbrosset (5811a67d0) - Bug 1144163 - Add a rulers highlighter; added highlighter. r=pbrosset (779f88bdd) - Bug 1144163 - Add a rulers highlighter; added gcli command and button. r=pbrosset (d0d13da51) - Bug 1110550 - Enable performance overview graphs to rerender and change on devtools theme switch. r=vp (bd91ca7cf) - Bug 1149630 - Performance graphs should inherit from a common graph and be similarly styled. r=vporof (481c841f1) - Bug 1150733 - Correctly internationalize jit samples label. r=vporof, r=flod (b5612d1a6) - Bug 1137518 - FlameGraph's destroy function should be async, r=jsantell (f103e4c15) - Bug 1137503 - Avoid potential infinite loops in `findOptimalTickInterval` functions, r=jsantell (95df6c04a) - Bug 1121194 - Support vertical panning for the flamegraph in the new performance tool, r=jsantell (06241b5b2) - Bug 1121180 - Support dark theme in flamecharts for the performance tool. r=vp (c76abe237) - Bug 1059308 - Add Target.isTabActor to tell if the remote tab actor supports attach/detach requests. r=jryans (e03dcef93) - Bug 1132370 - Wrong State: Expected 'attached', but current state is 'detached', r=jsantell (e884e8db9) - No Bug - Fix documentation for _startMemory and _stopMemory in performance/modules/front.js, r=me DONTBUILD (d79090b31) - Bug 1147656 - Remove duplicate profiler defaults from the front end and just use on the server. r=vp (35c015dd0) - Bug 1046234 - Add more DevTools Telemetry measures (display size etc) r=pbrosset, r=gijs (a235681b4) - actually package telemetry.js (e8f3a58a4) - Bug 1077464 - Wire console.profile/profileEnd to the new performance tool. Move most of the recording-model logic from the front end into the PerformanceFront and PerformanceActorConnection so it can manage recordings without the front end being viewed. r=vp,jryans,pbrosset (eef8e18c3) - Bug 1144363 - Fix this._telemetry is undefined in gDevTools. r=bgrins (ba7d02902) - init telemetry, missing parts of Bug 866642 (1e70df975) - do not use sysctl.h on Linux anymore, since it is not provided by recent glibc (b2467d7ce) - clean up some telemetry issues of histogram, parts of Bug 974171 (d30c8d0ad) - move devtools to browser - part 1 (9a856f452) - Bug 1291423: Explicitly qualify the destructor call that we invoke in Maybe::reset. r=Waldo (944904a7d) - Bug 1148075 - Dynamically add XUL commands for the debugger frontend. r=vporof (60bc91f8f) - Bug 1147945 - Let the profiler's buffer size and sample rate be configurable via prefs. r=vp (acebcbdd9) - Bug 1124326 - Improve packageDir support for Cordova. r=ochameau (4b736580a) - Bug 1124326 - Support Cordova w/o build file. r=ochameau (d4b50aeae) - Bug 1134029 - Fix 'Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIURI.host]' timeouts, r=jsantell (18d16a5d0) - Bug 1147806 - Content frame filtering is confused when profiling FxOS, r=jsantell (b3c62c552) - Bug 1108843 - Generalize platform data in call tree view when platform data is hidden. r=vporof (354553ed7) - Bug 1138928 - Display only function name and file, instead of full url, in flame graphs. r=vp (4169689c1) - Bug 1152605 - Should not show host names for chrome URIs. r=vporof (c6dcf9e78) - Bug 1147604 - Inverted call trees should list (root) as leaves. r=jsantell (01768267f) - Bug 1075450 - Disable some Awesomebar actions for private windows r=mak (21d5586e7) - Bug 1120616 - Part 1: Implement filter styles in rule view r=bgrins (b66ee0282) - Bug 1120616 - Part 2: Add unit tests for filter styles in rule view r=bgrins (2892503d8) - Bug 1120616 - Part 3: Adjust the styles in the computed view's filter style search r=bgrins (41f8fae1b) - Bug 1120616 - Part 4: Add textbox context menu for rule and computed view r=bgrins (ff3f868ad) - Bug 1120616 - Part 5: Refactor style inspector tests to use synthesizeKeys r=bgrins (41db021d7) - Bug 1102219 - Part 5: Replace more `String.prototype.contains` with `String.prototype.includes` in chrome code. r=till (86ed03588) - Bug 1154018 - Check to see that nsIURI's host exists when parsing location for framenodes, and cache failures. r=vp (9494d52e7) - Bug 1160691 - Optimize FrameUtils.isContent and FrameUtils.parseLocation. (r=jsantell) (09118fd5d) - Bug 1154115 - Make the performance devtool handle the new profiler JSON format. (r=jsantell,vporof) (e3e5be7a4) - Bug 1059308 - Make frame selection button to work in browser toolbox. r=jryans,past (30fe6e61e) - Bug 1059308 - Fix tests to support chrome actor. r=jryans (01cf3926c) - Bug 1147042 - Rename attachProcess to getProcess. r=ochameau (0393ffb80) - Bug 1145824 - Profiler actor and performance tools now handle passing in a startTime to filter out SPS profiles on platform rather than client. r=vp,fitzgen (f225116ba) - Bug 1157718 - Do not use Array.prototype.includes in production code that leaves nightly in performance tool. r=fitzgen (ff06d284e) - Bug 1140728 - Rename 'Memory' to 'Allocations' in the new performance tool. r=jsantell (f584e720f) - Bug 1137500 - Always wait for the overview to be rendered in tests after a recording finishes, unless otherwise specified, r=jsantell (59825e179) - Bug 1137487 - AbstractCanvasGraph's destroy function should be async, r=jsantell (a17ae00b5) - Bug 1132758 - Performance feature visibility now based on a per recording-basis, dependent on features enabled and server support. r=vp (0d080a7c2) - Bug 1147035 - Make DeveloperToolbar.jsm use the gBrowser.contentDocumentAsCPOW shortcut. r=past. (251eff125) - Bug 1151168 - Don't flush profiled threads that are pending deletion on JS shutdown and don't delete expired markers when resetting the profile buffer. (r=djvj) (90721313a)
876 lines
29 KiB
JavaScript
876 lines
29 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 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;
|
|
|
|
const NET_STRINGS_URI = "chrome://global/locale/devtools/netmonitor.properties";
|
|
const PKI_STRINGS_URI = "chrome://pippki/locale/pippki.properties";
|
|
const LISTENERS = [ "NetworkActivity" ];
|
|
const NET_PREFS = { "NetworkMonitor.saveRequestAndResponseBodies": true };
|
|
|
|
// The panel's window global is an EventEmitter firing the following events:
|
|
const EVENTS = {
|
|
// When the monitored target begins and finishes navigating.
|
|
TARGET_WILL_NAVIGATE: "NetMonitor:TargetWillNavigate",
|
|
TARGET_DID_NAVIGATE: "NetMonitor:TargetNavigate",
|
|
|
|
// When a network event is received.
|
|
// See https://developer.mozilla.org/docs/Tools/Web_Console/remoting for
|
|
// more information about what each packet is supposed to deliver.
|
|
NETWORK_EVENT: "NetMonitor:NetworkEvent",
|
|
|
|
// When request headers begin and finish receiving.
|
|
UPDATING_REQUEST_HEADERS: "NetMonitor:NetworkEventUpdating:RequestHeaders",
|
|
RECEIVED_REQUEST_HEADERS: "NetMonitor:NetworkEventUpdated:RequestHeaders",
|
|
|
|
// When request cookies begin and finish receiving.
|
|
UPDATING_REQUEST_COOKIES: "NetMonitor:NetworkEventUpdating:RequestCookies",
|
|
RECEIVED_REQUEST_COOKIES: "NetMonitor:NetworkEventUpdated:RequestCookies",
|
|
|
|
// When request post data begins and finishes receiving.
|
|
UPDATING_REQUEST_POST_DATA: "NetMonitor:NetworkEventUpdating:RequestPostData",
|
|
RECEIVED_REQUEST_POST_DATA: "NetMonitor:NetworkEventUpdated:RequestPostData",
|
|
|
|
// When security information begins and finishes receiving.
|
|
UPDATING_SECURITY_INFO: "NetMonitor::NetworkEventUpdating:SecurityInfo",
|
|
RECEIVED_SECURITY_INFO: "NetMonitor::NetworkEventUpdated:SecurityInfo",
|
|
|
|
// When response headers begin and finish receiving.
|
|
UPDATING_RESPONSE_HEADERS: "NetMonitor:NetworkEventUpdating:ResponseHeaders",
|
|
RECEIVED_RESPONSE_HEADERS: "NetMonitor:NetworkEventUpdated:ResponseHeaders",
|
|
|
|
// When response cookies begin and finish receiving.
|
|
UPDATING_RESPONSE_COOKIES: "NetMonitor:NetworkEventUpdating:ResponseCookies",
|
|
RECEIVED_RESPONSE_COOKIES: "NetMonitor:NetworkEventUpdated:ResponseCookies",
|
|
|
|
// When event timings begin and finish receiving.
|
|
UPDATING_EVENT_TIMINGS: "NetMonitor:NetworkEventUpdating:EventTimings",
|
|
RECEIVED_EVENT_TIMINGS: "NetMonitor:NetworkEventUpdated:EventTimings",
|
|
|
|
// When response content begins, updates and finishes receiving.
|
|
STARTED_RECEIVING_RESPONSE: "NetMonitor:NetworkEventUpdating:ResponseStart",
|
|
UPDATING_RESPONSE_CONTENT: "NetMonitor:NetworkEventUpdating:ResponseContent",
|
|
RECEIVED_RESPONSE_CONTENT: "NetMonitor:NetworkEventUpdated:ResponseContent",
|
|
|
|
// When the request post params are displayed in the UI.
|
|
REQUEST_POST_PARAMS_DISPLAYED: "NetMonitor:RequestPostParamsAvailable",
|
|
|
|
// When the response body is displayed in the UI.
|
|
RESPONSE_BODY_DISPLAYED: "NetMonitor:ResponseBodyAvailable",
|
|
|
|
// When the html response preview is displayed in the UI.
|
|
RESPONSE_HTML_PREVIEW_DISPLAYED: "NetMonitor:ResponseHtmlPreviewAvailable",
|
|
|
|
// When the image response thumbnail is displayed in the UI.
|
|
RESPONSE_IMAGE_THUMBNAIL_DISPLAYED: "NetMonitor:ResponseImageThumbnailAvailable",
|
|
|
|
// When a tab is selected in the NetworkDetailsView and subsequently rendered.
|
|
TAB_UPDATED: "NetMonitor:TabUpdated",
|
|
|
|
// Fired when Sidebar has finished being populated.
|
|
SIDEBAR_POPULATED: "NetMonitor:SidebarPopulated",
|
|
|
|
// Fired when NetworkDetailsView has finished being populated.
|
|
NETWORKDETAILSVIEW_POPULATED: "NetMonitor:NetworkDetailsViewPopulated",
|
|
|
|
// Fired when CustomRequestView has finished being populated.
|
|
CUSTOMREQUESTVIEW_POPULATED: "NetMonitor:CustomRequestViewPopulated",
|
|
|
|
// Fired when charts have been displayed in the PerformanceStatisticsView.
|
|
PLACEHOLDER_CHARTS_DISPLAYED: "NetMonitor:PlaceholderChartsDisplayed",
|
|
PRIMED_CACHE_CHART_DISPLAYED: "NetMonitor:PrimedChartsDisplayed",
|
|
EMPTY_CACHE_CHART_DISPLAYED: "NetMonitor:EmptyChartsDisplayed",
|
|
|
|
// Fired once the NetMonitorController establishes a connection to the debug
|
|
// target.
|
|
CONNECTED: "connected",
|
|
};
|
|
|
|
// Descriptions for what this frontend is currently doing.
|
|
const ACTIVITY_TYPE = {
|
|
// Standing by and handling requests normally.
|
|
NONE: 0,
|
|
|
|
// Forcing the target to reload with cache enabled or disabled.
|
|
RELOAD: {
|
|
WITH_CACHE_ENABLED: 1,
|
|
WITH_CACHE_DISABLED: 2,
|
|
WITH_CACHE_DEFAULT: 3
|
|
},
|
|
|
|
// Enabling or disabling the cache without triggering a reload.
|
|
ENABLE_CACHE: 3,
|
|
DISABLE_CACHE: 4
|
|
};
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
Cu.import("resource://gre/modules/devtools/SideMenuWidget.jsm");
|
|
Cu.import("resource://gre/modules/devtools/VariablesView.jsm");
|
|
Cu.import("resource://gre/modules/devtools/VariablesViewController.jsm");
|
|
Cu.import("resource://gre/modules/devtools/ViewHelpers.jsm");
|
|
|
|
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
|
const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
|
const EventEmitter = require("devtools/toolkit/event-emitter");
|
|
const Editor = require("devtools/sourceeditor/editor");
|
|
const {Tooltip} = require("devtools/shared/widgets/Tooltip");
|
|
const {ToolSidebar} = require("devtools/framework/sidebar");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Chart",
|
|
"resource://gre/modules/devtools/Chart.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Curl",
|
|
"resource://gre/modules/devtools/Curl.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "CurlUtils",
|
|
"resource://gre/modules/devtools/Curl.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
|
"resource://gre/modules/Task.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
|
"resource://gre/modules/PluralForm.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "DevToolsUtils",
|
|
"resource://gre/modules/devtools/DevToolsUtils.jsm");
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
|
|
"@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "DOMParser",
|
|
"@mozilla.org/xmlextras/domparser;1", "nsIDOMParser");
|
|
|
|
Object.defineProperty(this, "NetworkHelper", {
|
|
get: function() {
|
|
return require("devtools/toolkit/webconsole/network-helper");
|
|
},
|
|
configurable: true,
|
|
enumerable: 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._startup) {
|
|
return this._startup;
|
|
}
|
|
|
|
NetMonitorView.initialize();
|
|
|
|
// Startup is synchronous, for now.
|
|
return this._startup = promise.resolve();
|
|
},
|
|
|
|
/**
|
|
* 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._shutdown) {
|
|
return this._shutdown;
|
|
}
|
|
|
|
NetMonitorView.destroy();
|
|
this.TargetEventsHandler.disconnect();
|
|
this.NetworkEventsHandler.disconnect();
|
|
this.disconnect();
|
|
|
|
// Shutdown is synchronous, for now.
|
|
return this._shutdown = promise.resolve();
|
|
},
|
|
|
|
/**
|
|
* 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: Task.async(function*() {
|
|
if (this._connection) {
|
|
return this._connection;
|
|
}
|
|
|
|
let deferred = promise.defer();
|
|
this._connection = deferred.promise;
|
|
|
|
let target = this._target;
|
|
let { client, form } = target;
|
|
// Some actors like AddonActor or RootActor for chrome debugging
|
|
// do not support attach/detach and can be used directly
|
|
if (!target.isTabActor) {
|
|
this._startChromeMonitoring(client, form.consoleActor, deferred.resolve);
|
|
} else {
|
|
this._startMonitoringTab(client, form, deferred.resolve);
|
|
}
|
|
|
|
yield deferred.promise;
|
|
window.emit(EVENTS.CONNECTED);
|
|
}),
|
|
|
|
/**
|
|
* 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;
|
|
},
|
|
|
|
/**
|
|
* Checks whether the netmonitor connection is active.
|
|
* @return boolean
|
|
*/
|
|
isConnected: function() {
|
|
return !!this.client;
|
|
},
|
|
|
|
/**
|
|
* 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();
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Gets the activity currently performed by the frontend.
|
|
* @return number
|
|
*/
|
|
getCurrentActivity: function() {
|
|
return this._currentActivity || ACTIVITY_TYPE.NONE;
|
|
},
|
|
|
|
/**
|
|
* Triggers a specific "activity" to be performed by the frontend. This can be,
|
|
* for example, triggering reloads or enabling/disabling cache.
|
|
*
|
|
* @param number aType
|
|
* The activity type. See the ACTIVITY_TYPE const.
|
|
* @return object
|
|
* A promise resolved once the activity finishes and the frontend
|
|
* is back into "standby" mode.
|
|
*/
|
|
triggerActivity: function(aType) {
|
|
// Puts the frontend into "standby" (when there's no particular activity).
|
|
let standBy = () => {
|
|
this._currentActivity = ACTIVITY_TYPE.NONE;
|
|
};
|
|
|
|
// Waits for a series of "navigation start" and "navigation stop" events.
|
|
let waitForNavigation = () => {
|
|
let deferred = promise.defer();
|
|
this._target.once("will-navigate", () => {
|
|
this._target.once("navigate", () => {
|
|
deferred.resolve();
|
|
});
|
|
});
|
|
return deferred.promise;
|
|
};
|
|
|
|
// Reconfigures the tab, optionally triggering a reload.
|
|
let reconfigureTab = aOptions => {
|
|
let deferred = promise.defer();
|
|
this._target.activeTab.reconfigure(aOptions, deferred.resolve);
|
|
return deferred.promise;
|
|
};
|
|
|
|
// Reconfigures the tab and waits for the target to finish navigating.
|
|
let reconfigureTabAndWaitForNavigation = aOptions => {
|
|
aOptions.performReload = true;
|
|
let navigationFinished = waitForNavigation();
|
|
return reconfigureTab(aOptions).then(() => navigationFinished);
|
|
}
|
|
if (aType == ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT) {
|
|
return reconfigureTabAndWaitForNavigation({}).then(standBy);
|
|
}
|
|
if (aType == ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED) {
|
|
this._currentActivity = ACTIVITY_TYPE.ENABLE_CACHE;
|
|
this._target.once("will-navigate", () => this._currentActivity = aType);
|
|
return reconfigureTabAndWaitForNavigation({ cacheDisabled: false, performReload: true }).then(standBy);
|
|
}
|
|
if (aType == ACTIVITY_TYPE.RELOAD.WITH_CACHE_DISABLED) {
|
|
this._currentActivity = ACTIVITY_TYPE.DISABLE_CACHE;
|
|
this._target.once("will-navigate", () => this._currentActivity = aType);
|
|
return reconfigureTabAndWaitForNavigation({ cacheDisabled: true, performReload: true }).then(standBy);
|
|
}
|
|
if (aType == ACTIVITY_TYPE.ENABLE_CACHE) {
|
|
this._currentActivity = aType;
|
|
return reconfigureTab({ cacheDisabled: false, performReload: false }).then(standBy);
|
|
}
|
|
if (aType == ACTIVITY_TYPE.DISABLE_CACHE) {
|
|
this._currentActivity = aType;
|
|
return reconfigureTab({ cacheDisabled: true, performReload: false }).then(standBy);
|
|
}
|
|
this._currentActivity = ACTIVITY_TYPE.NONE;
|
|
return promise.reject(new Error("Invalid activity type"));
|
|
},
|
|
|
|
/**
|
|
* Getter that tells if the server supports sending custom network requests.
|
|
* @type boolean
|
|
*/
|
|
get supportsCustomRequest() {
|
|
return this.webConsoleClient &&
|
|
(this.webConsoleClient.traits.customNetworkRequest ||
|
|
!this._target.isApp);
|
|
},
|
|
|
|
/**
|
|
* Getter that tells if the server includes the transferred (compressed /
|
|
* encoded) response size.
|
|
* @type boolean
|
|
*/
|
|
get supportsTransferredResponseSize() {
|
|
return this.webConsoleClient &&
|
|
this.webConsoleClient.traits.transferredResponseSize;
|
|
},
|
|
|
|
/**
|
|
* Getter that tells if the server can do network performance statistics.
|
|
* @type boolean
|
|
*/
|
|
get supportsPerfStats() {
|
|
return this.tabClient &&
|
|
(this.tabClient.traits.reconfigure || !this._target.isApp);
|
|
},
|
|
|
|
_startup: null,
|
|
_shutdown: null,
|
|
_connection: null,
|
|
_currentActivity: 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.
|
|
if (!Services.prefs.getBoolPref("devtools.webconsole.persistlog")) {
|
|
NetMonitorView.RequestsMenu.reset();
|
|
NetMonitorView.Sidebar.toggle(false);
|
|
}
|
|
// Switch to the default network traffic inspector view.
|
|
if (NetMonitorController.getCurrentActivity() == ACTIVITY_TYPE.NONE) {
|
|
NetMonitorView.showNetworkInspectorView();
|
|
}
|
|
|
|
window.emit(EVENTS.TARGET_WILL_NAVIGATE);
|
|
break;
|
|
}
|
|
case "navigate": {
|
|
window.emit(EVENTS.TARGET_DID_NAVIGATE);
|
|
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) {
|
|
if (aPacket.from != this.webConsoleClient.actor) {
|
|
// Skip events from different console actors.
|
|
return;
|
|
}
|
|
|
|
let { actor, startedDateTime, method, url, isXHR } = aPacket.eventActor;
|
|
NetMonitorView.RequestsMenu.addRequest(actor, startedDateTime, method, url, isXHR);
|
|
window.emit(EVENTS.NETWORK_EVENT, actor);
|
|
},
|
|
|
|
/**
|
|
* 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;
|
|
if (!NetMonitorView.RequestsMenu.getItemByValue(actor)) {
|
|
// Skip events from unknown actors.
|
|
return;
|
|
}
|
|
|
|
switch (aPacket.updateType) {
|
|
case "requestHeaders":
|
|
this.webConsoleClient.getRequestHeaders(actor, this._onRequestHeaders);
|
|
window.emit(EVENTS.UPDATING_REQUEST_HEADERS, actor);
|
|
break;
|
|
case "requestCookies":
|
|
this.webConsoleClient.getRequestCookies(actor, this._onRequestCookies);
|
|
window.emit(EVENTS.UPDATING_REQUEST_COOKIES, actor);
|
|
break;
|
|
case "requestPostData":
|
|
this.webConsoleClient.getRequestPostData(actor, this._onRequestPostData);
|
|
window.emit(EVENTS.UPDATING_REQUEST_POST_DATA, actor);
|
|
break;
|
|
case "securityInfo":
|
|
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
|
|
securityState: aPacket.state,
|
|
});
|
|
this.webConsoleClient.getSecurityInfo(actor, this._onSecurityInfo);
|
|
window.emit(EVENTS.UPDATING_SECURITY_INFO, actor);
|
|
break;
|
|
case "responseHeaders":
|
|
this.webConsoleClient.getResponseHeaders(actor, this._onResponseHeaders);
|
|
window.emit(EVENTS.UPDATING_RESPONSE_HEADERS, actor);
|
|
break;
|
|
case "responseCookies":
|
|
this.webConsoleClient.getResponseCookies(actor, this._onResponseCookies);
|
|
window.emit(EVENTS.UPDATING_RESPONSE_COOKIES, actor);
|
|
break;
|
|
case "responseStart":
|
|
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
|
|
httpVersion: aPacket.response.httpVersion,
|
|
remoteAddress: aPacket.response.remoteAddress,
|
|
remotePort: aPacket.response.remotePort,
|
|
status: aPacket.response.status,
|
|
statusText: aPacket.response.statusText,
|
|
headersSize: aPacket.response.headersSize
|
|
});
|
|
window.emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor);
|
|
break;
|
|
case "responseContent":
|
|
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
|
|
contentSize: aPacket.contentSize,
|
|
transferredSize: aPacket.transferredSize,
|
|
mimeType: aPacket.mimeType
|
|
});
|
|
this.webConsoleClient.getResponseContent(actor, this._onResponseContent);
|
|
window.emit(EVENTS.UPDATING_RESPONSE_CONTENT, actor);
|
|
break;
|
|
case "eventTimings":
|
|
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
|
|
totalTime: aPacket.totalTime
|
|
});
|
|
this.webConsoleClient.getEventTimings(actor, this._onEventTimings);
|
|
window.emit(EVENTS.UPDATING_EVENT_TIMINGS, actor);
|
|
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(EVENTS.RECEIVED_REQUEST_HEADERS, aResponse.from);
|
|
},
|
|
|
|
/**
|
|
* 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(EVENTS.RECEIVED_REQUEST_COOKIES, aResponse.from);
|
|
},
|
|
|
|
/**
|
|
* 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(EVENTS.RECEIVED_REQUEST_POST_DATA, aResponse.from);
|
|
},
|
|
|
|
/**
|
|
* Handles additional information received for a "securityInfo" packet.
|
|
*
|
|
* @param object aResponse
|
|
* The message received from the server.
|
|
*/
|
|
_onSecurityInfo: function(aResponse) {
|
|
NetMonitorView.RequestsMenu.updateRequest(aResponse.from, {
|
|
securityInfo: aResponse.securityInfo
|
|
});
|
|
|
|
window.emit(EVENTS.RECEIVED_SECURITY_INFO, aResponse.from);
|
|
},
|
|
|
|
/**
|
|
* 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(EVENTS.RECEIVED_RESPONSE_HEADERS, aResponse.from);
|
|
},
|
|
|
|
/**
|
|
* 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(EVENTS.RECEIVED_RESPONSE_COOKIES, aResponse.from);
|
|
},
|
|
|
|
/**
|
|
* 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(EVENTS.RECEIVED_RESPONSE_CONTENT, aResponse.from);
|
|
},
|
|
|
|
/**
|
|
* 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(EVENTS.RECEIVED_EVENT_TIMINGS, aResponse.from);
|
|
},
|
|
|
|
/**
|
|
* 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);
|
|
let PKI_L10N = new ViewHelpers.L10N(PKI_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"],
|
|
statistics: ["Bool", "statistics"],
|
|
filters: ["Json", "filters"]
|
|
});
|
|
|
|
/**
|
|
* 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,
|
|
configurable: true
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Makes sure certain properties are available on all objects in a data store.
|
|
*
|
|
* @param array aDataStore
|
|
* A list of objects for which to check the availability of properties.
|
|
* @param array aMandatoryFields
|
|
* A list of strings representing properties of objects in aDataStore.
|
|
* @return object
|
|
* A promise resolved when all objects in aDataStore contain the
|
|
* properties defined in aMandatoryFields.
|
|
*/
|
|
function whenDataAvailable(aDataStore, aMandatoryFields) {
|
|
let deferred = promise.defer();
|
|
|
|
let interval = setInterval(() => {
|
|
if (aDataStore.every(item => aMandatoryFields.every(field => field in item))) {
|
|
clearInterval(interval);
|
|
clearTimeout(timer);
|
|
deferred.resolve();
|
|
}
|
|
}, WDA_DEFAULT_VERIFY_INTERVAL);
|
|
|
|
let timer = setTimeout(() => {
|
|
clearInterval(interval);
|
|
deferred.reject(new Error("Timed out while waiting for data"));
|
|
}, WDA_DEFAULT_GIVE_UP_TIMEOUT);
|
|
|
|
return deferred.promise;
|
|
};
|
|
|
|
const WDA_DEFAULT_VERIFY_INTERVAL = 50; // ms
|
|
|
|
// Use longer timeout during testing as the tests need this process to succeed
|
|
// and two seconds is quite short on slow debug builds. The timeout here should
|
|
// be at least equal to the general mochitest timeout of 45 seconds so that this
|
|
// never gets hit during testing.
|
|
const WDA_DEFAULT_GIVE_UP_TIMEOUT = gDevTools.testing ? 45000 : 2000; // ms
|
|
|
|
/**
|
|
* Helper method for debugging.
|
|
* @param string
|
|
*/
|
|
function dumpn(str) {
|
|
if (wantLogging) {
|
|
dump("NET-FRONTEND: " + str + "\n");
|
|
}
|
|
}
|
|
|
|
let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|