--- a/devtools/client/netmonitor/index.html
+++ b/devtools/client/netmonitor/index.html
@@ -21,39 +21,42 @@
}).require;
const EventEmitter = require("devtools/shared/event-emitter");
const { createFactory } = require("devtools/client/shared/vendor/react");
const { render, unmountComponentAtNode } = require("devtools/client/shared/vendor/react-dom");
const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
const { configureStore } = require("./src/utils/create-store");
- const store = window.gStore = configureStore();
+ const store = configureStore();
const actions = bindActionCreators(require("./src/actions/index"), store.dispatch);
- const { NetMonitorController } = require("./src/netmonitor-controller");
+ const { onFirefoxConnect, onDisconnect } = require("./src/connector/index");
// Inject EventEmitter into global window.
EventEmitter.decorate(window);
+ // Inject to global window for testing
+ window.store = store;
window.Netmonitor = {
bootstrap({ toolbox }) {
this.mount = document.querySelector("#mount");
- const App = createFactory(require("./src/components/app"));
- render(Provider({ store }, App()), this.mount);
- return NetMonitorController.startupNetMonitor({
+ const connection = {
tabConnection: {
tabTarget: toolbox.target,
},
toolbox,
- }, actions);
+ };
+ const App = createFactory(require("./src/components/app"));
+ render(Provider({ store }, App()), this.mount);
+ return onFirefoxConnect(connection, actions, store.getState);
},
destroy() {
unmountComponentAtNode(this.mount);
- return NetMonitorController.shutdownNetMonitor();
+ return onDisconnect();
}
};
// Implement support for chrome://devtools/content/netmonitor/index.html?type=tab&id=1234 URLs
// where 1234 is the tab id, you can retrieve from about:debugging#tabs links.
// Simply copy the id from about:devtools-toolbox?type=tab&id=1234 URLs.
// URL constructor doesn't support chrome: scheme
--- a/devtools/client/netmonitor/index.js
+++ b/devtools/client/netmonitor/index.js
@@ -34,19 +34,22 @@ pref("devtools.netmonitor.har.jsonpCallb
pref("devtools.netmonitor.har.includeResponseBodies", true);
pref("devtools.netmonitor.har.compress", false);
pref("devtools.netmonitor.har.forceExport", false);
pref("devtools.netmonitor.har.pageLoadedTimeout", 1500);
pref("devtools.netmonitor.har.enableAutoExportToFile", false);
pref("devtools.webconsole.persistlog", false);
const App = require("./src/components/app");
-const store = window.gStore = configureStore();
+const store = configureStore();
const actions = bindActionCreators(require("./src/actions"), store.dispatch);
-const { NetMonitorController } = require("./src/netmonitor-controller");
+const { onConnect } = require("./src/connector");
+
+// Inject to global window for testing
+window.store = store;
/**
* Stylesheet links in devtools xhtml files are using chrome or resource URLs.
* Rewrite the href attribute to remove the protocol. web-server.js contains redirects
* to map CSS urls to the proper file. Supports urls using:
* - devtools/client/
* - devtools/content/
* - skin/
@@ -62,15 +65,15 @@ window.addEventListener("DOMContentLoade
document.documentElement.setAttribute("platform", "mac");
} else if (appinfo.OS === "Linux") {
document.documentElement.setAttribute("platform", "linux");
} else {
document.documentElement.setAttribute("platform", "win");
}
});
-bootstrap(React, ReactDOM).then(connection => {
+bootstrap(React, ReactDOM).then((connection) => {
if (!connection) {
return;
}
renderRoot(React, ReactDOM, App, store);
- NetMonitorController.startupNetMonitor(connection, actions);
+ onConnect(connection, actions, store.getState);
});
--- a/devtools/client/netmonitor/src/actions/requests.js
+++ b/devtools/client/netmonitor/src/actions/requests.js
@@ -1,23 +1,23 @@
/* 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 { sendHTTPRequest } = require("../connector/index");
const {
ADD_REQUEST,
CLEAR_REQUESTS,
CLONE_SELECTED_REQUEST,
REMOVE_SELECTED_CUSTOM_REQUEST,
SEND_CUSTOM_REQUEST,
UPDATE_REQUEST,
} = require("../constants");
-const { NetMonitorController } = require("../netmonitor-controller");
const { getSelectedRequest } = require("../selectors/index");
function addRequest(id, data, batch) {
return {
type: ADD_REQUEST,
id,
data,
meta: { batch },
@@ -42,20 +42,16 @@ function cloneSelectedRequest() {
type: CLONE_SELECTED_REQUEST
};
}
/**
* Send a new HTTP request using the data in the custom request form.
*/
function sendCustomRequest() {
- if (!NetMonitorController.supportsCustomRequest) {
- return cloneSelectedRequest();
- }
-
return (dispatch, getState) => {
const selected = getSelectedRequest(getState());
if (!selected) {
return;
}
// Send a new HTTP request using the data in the custom request form
@@ -66,17 +62,17 @@ function sendCustomRequest() {
};
if (selected.requestHeaders) {
data.headers = selected.requestHeaders.headers;
}
if (selected.requestPostData) {
data.body = selected.requestPostData.postData.text;
}
- NetMonitorController.webConsoleClient.sendHTTPRequest(data, (response) => {
+ sendHTTPRequest(data, (response) => {
return dispatch({
type: SEND_CUSTOM_REQUEST,
id: response.eventActor.actor,
});
});
};
}
--- a/devtools/client/netmonitor/src/actions/ui.js
+++ b/devtools/client/netmonitor/src/actions/ui.js
@@ -8,17 +8,17 @@ const {
ACTIVITY_TYPE,
OPEN_NETWORK_DETAILS,
OPEN_STATISTICS,
RESET_COLUMNS,
SELECT_DETAILS_PANEL_TAB,
TOGGLE_COLUMN,
WATERFALL_RESIZE,
} = require("../constants");
-const { NetMonitorController } = require("../netmonitor-controller");
+const { triggerActivity } = require("../connector/index");
/**
* Change network details panel.
*
* @param {boolean} open - expected network details panel open state
*/
function openNetworkDetails(open) {
return {
@@ -29,17 +29,17 @@ function openNetworkDetails(open) {
/**
* Change performance statistics panel open state.
*
* @param {boolean} visible - expected performance statistics panel open state
*/
function openStatistics(open) {
if (open) {
- NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
+ triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
}
return {
type: OPEN_STATISTICS,
open,
};
}
/**
--- a/devtools/client/netmonitor/src/components/headers-panel.js
+++ b/devtools/client/netmonitor/src/components/headers-panel.js
@@ -5,17 +5,16 @@
"use strict";
const {
createClass,
createFactory,
DOM,
PropTypes,
} = require("devtools/client/shared/vendor/react");
-const { NetMonitorController } = require("../netmonitor-controller");
const {
getFormattedIPAndPort,
getFormattedSize,
} = require("../utils/format-utils");
const { L10N } = require("../utils/l10n");
const {
getHeadersURL,
getHTTPStatusCodeURL,
@@ -196,17 +195,17 @@ const HeadersPanel = createClass({
+ " status-text",
readOnly: true,
value: `${status} ${statusText}`,
size: `${inputWidth}`,
}),
statusCodeDocURL ? MDNLink({
url: statusCodeDocURL,
}) : null,
- NetMonitorController.supportsCustomRequest && button({
+ button({
className: "devtools-button",
onClick: cloneSelectedRequest,
}, EDIT_AND_RESEND),
button({
className: "devtools-button",
onClick: this.toggleRawHeaders,
}, RAW_HEADERS),
)
--- a/devtools/client/netmonitor/src/components/monitor-panel.js
+++ b/devtools/client/netmonitor/src/components/monitor-panel.js
@@ -9,17 +9,17 @@ const {
createClass,
createFactory,
DOM,
PropTypes,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
const Actions = require("../actions/index");
-const { getLongString } = require("../utils/client");
+const { getLongString } = require("../connector/index");
const { getFormDataSections } = require("../utils/request-utils");
const { getSelectedRequest } = require("../selectors/index");
// Components
const SplitBox = createFactory(require("devtools/client/shared/components/splitter/split-box"));
const NetworkDetailsPanel = createFactory(require("./network-details-panel"));
const RequestList = createFactory(require("./request-list"));
const Toolbar = createFactory(require("./toolbar"));
--- a/devtools/client/netmonitor/src/components/request-list-empty-notice.js
+++ b/devtools/client/netmonitor/src/components/request-list-empty-notice.js
@@ -7,18 +7,18 @@
const {
createClass,
createFactory,
DOM,
PropTypes,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const Actions = require("../actions/index");
+const { triggerActivity } = require("../connector/index");
const { ACTIVITY_TYPE } = require("../constants");
-const { NetMonitorController } = require("../netmonitor-controller");
const { L10N } = require("../utils/l10n");
const { getPerformanceAnalysisURL } = require("../utils/mdn-utils");
// Components
const MDNLink = createFactory(require("./mdn-link"));
const { button, div, span } = DOM;
@@ -65,13 +65,11 @@ const RequestListEmptyNotice = createCla
);
}
});
module.exports = connect(
undefined,
dispatch => ({
onPerfClick: () => dispatch(Actions.openStatistics(true)),
- onReloadClick: () =>
- NetMonitorController
- .triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT),
+ onReloadClick: () => triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT),
})
)(RequestListEmptyNotice);
--- a/devtools/client/netmonitor/src/components/stack-trace-panel.js
+++ b/devtools/client/netmonitor/src/components/stack-trace-panel.js
@@ -4,32 +4,31 @@
"use strict";
const {
createFactory,
DOM,
PropTypes,
} = require("devtools/client/shared/vendor/react");
+const { viewSourceInDebugger } = require("../connector/index");
const { div } = DOM;
// Components
const StackTrace = createFactory(require("devtools/client/shared/components/stack-trace"));
function StackTracePanel({ request }) {
let { stacktrace } = request.cause;
return (
div({ className: "panel-container" },
StackTrace({
stacktrace,
- onViewSourceInDebugger: (frame) => {
- window.NetMonitorController.viewSourceInDebugger(frame.url, frame.line);
- },
+ onViewSourceInDebugger: ({ url, line }) => viewSourceInDebugger(url, line),
}),
)
);
}
StackTracePanel.displayName = "StackTracePanel";
StackTracePanel.propTypes = {
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/src/connector/firefox-connector.js
@@ -0,0 +1,724 @@
+/* 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 Services = require("Services");
+const { CurlUtils } = require("devtools/client/shared/curl");
+const { TimelineFront } = require("devtools/shared/fronts/timeline");
+const { ACTIVITY_TYPE, EVENTS } = require("../constants");
+const { getDisplayedRequestById } = require("../selectors/index");
+const { fetchHeaders, formDataURI } = require("../utils/request-utils");
+
+class FirefoxConnector {
+ constructor() {
+ this.connect = this.connect.bind(this);
+ this.disconnect = this.disconnect.bind(this);
+ this.willNavigate = this.willNavigate.bind(this);
+ this.displayCachedEvents = this.displayCachedEvents.bind(this);
+ this.onDocLoadingMarker = this.onDocLoadingMarker.bind(this);
+ this.addRequest = this.addRequest.bind(this);
+ this.updateRequest = this.updateRequest.bind(this);
+ this.fetchImage = this.fetchImage.bind(this);
+ this.fetchRequestHeaders = this.fetchRequestHeaders.bind(this);
+ this.fetchResponseHeaders = this.fetchResponseHeaders.bind(this);
+ this.fetchPostData = this.fetchPostData.bind(this);
+ this.fetchResponseCookies = this.fetchResponseCookies.bind(this);
+ this.fetchRequestCookies = this.fetchRequestCookies.bind(this);
+ this.getPayloadFromQueue = this.getPayloadFromQueue.bind(this);
+ this.isQueuePayloadReady = this.isQueuePayloadReady.bind(this);
+ this.pushPayloadToQueue = this.pushPayloadToQueue.bind(this);
+ this.sendHTTPRequest = this.sendHTTPRequest.bind(this);
+ this.setPreferences = this.setPreferences.bind(this);
+ this.triggerActivity = this.triggerActivity.bind(this);
+ this.inspectRequest = this.inspectRequest.bind(this);
+ this.getLongString = this.getLongString.bind(this);
+ this.getNetworkRequest = this.getNetworkRequest.bind(this);
+ this.getTabTarget = this.getTabTarget.bind(this);
+ this.viewSourceInDebugger = this.viewSourceInDebugger.bind(this);
+
+ // Event handlers
+ 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.onSecurityInfo = this.onSecurityInfo.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);
+ }
+
+ async connect(connection, actions, getState) {
+ this.actions = actions;
+ this.getState = getState;
+ this.tabTarget = connection.tabConnection.tabTarget;
+ this.tabClient = this.tabTarget.isTabActor ? this.tabTarget.activeTab : null;
+ this.webConsoleClient = this.tabTarget.activeConsole;
+
+ this.tabTarget.on("will-navigate", this.willNavigate);
+ this.tabTarget.on("close", this.disconnect);
+ this.webConsoleClient.on("networkEvent", this.onNetworkEvent);
+ this.webConsoleClient.on("networkEventUpdate", this.onNetworkEventUpdate);
+
+ // Don't start up waiting for timeline markers if the server isn't
+ // recent enough to emit the markers we're interested in.
+ if (this.tabTarget.getTrait("documentLoadingMarkers")) {
+ this.timelineFront = new TimelineFront(this.tabTarget.client, this.tabTarget.form);
+ this.timelineFront.on("doc-loading", this.onDocLoadingMarker);
+ await this.timelineFront.start({ withDocLoadingEvents: true });
+ }
+
+ this.displayCachedEvents();
+ }
+
+ async disconnect() {
+ // When debugging local or a remote instance, the connection is closed by
+ // the RemoteTarget. The webconsole actor is stopped on disconnect.
+ this.tabClient = null;
+ this.webConsoleClient = null;
+
+ // The timeline front wasn't initialized and started if the server wasn't
+ // recent enough to emit the markers we were interested in.
+ if (this.tabTarget.getTrait("documentLoadingMarkers") && this.timelineFront) {
+ this.timelineFront.off("doc-loading", this.onDocLoadingMarker);
+ await this.timelineFront.destroy();
+ this.timelineFront = null;
+ }
+ }
+
+ willNavigate() {
+ if (!Services.prefs.getBoolPref("devtools.webconsole.persistlog")) {
+ this.actions.batchReset();
+ this.actions.clearRequests();
+ } else {
+ // If the log is persistent, just clear all accumulated timing markers.
+ this.actions.clearTimingMarkers();
+ }
+ }
+
+ /**
+ * Display any network events already in the cache.
+ */
+ displayCachedEvents() {
+ for (let networkInfo of this.webConsoleClient.getNetworkEvents()) {
+ // First add the request to the timeline.
+ this.onNetworkEvent("networkEvent", networkInfo);
+ // Then replay any updates already received.
+ for (let updateType of networkInfo.updates) {
+ this.onNetworkEventUpdate("networkEventUpdate", {
+ packet: { updateType },
+ networkInfo,
+ });
+ }
+ }
+ }
+
+ /**
+ * The "DOMContentLoaded" and "Load" events sent by the timeline actor.
+ *
+ * @param {object} marker
+ */
+ onDocLoadingMarker(marker) {
+ window.emit(EVENTS.TIMELINE_EVENT, marker);
+ this.actions.addTimingMarker(marker);
+ }
+
+ /**
+ * Add a new network request to application state.
+ *
+ * @param {string} id request id
+ * @param {object} data data payload will be added to application state
+ */
+ addRequest(id, data) {
+ let {
+ method,
+ url,
+ isXHR,
+ cause,
+ startedDateTime,
+ fromCache,
+ fromServiceWorker,
+ } = data;
+
+ this.actions.addRequest(
+ id,
+ {
+ // Convert the received date/time string to a unix timestamp.
+ startedMillis: Date.parse(startedDateTime),
+ method,
+ url,
+ isXHR,
+ cause,
+ fromCache,
+ fromServiceWorker,
+ },
+ true,
+ )
+ .then(() => window.emit(EVENTS.REQUEST_ADDED, id));
+ }
+
+ /**
+ * Update a network request if it already exists in application state.
+ *
+ * @param {string} id request id
+ * @param {object} data data payload will be updated to application state
+ */
+ async updateRequest(id, data) {
+ let {
+ mimeType,
+ responseContent,
+ responseCookies,
+ responseHeaders,
+ requestCookies,
+ requestHeaders,
+ requestPostData,
+ } = data;
+
+ // fetch request detail contents in parallel
+ let [
+ imageObj,
+ requestHeadersObj,
+ responseHeadersObj,
+ postDataObj,
+ requestCookiesObj,
+ responseCookiesObj,
+ ] = await Promise.all([
+ this.fetchImage(mimeType, responseContent),
+ this.fetchRequestHeaders(requestHeaders),
+ this.fetchResponseHeaders(responseHeaders),
+ this.fetchPostData(requestPostData),
+ this.fetchRequestCookies(requestCookies),
+ this.fetchResponseCookies(responseCookies),
+ ]);
+
+ let payload = Object.assign({}, data,
+ imageObj, requestHeadersObj, responseHeadersObj,
+ postDataObj, requestCookiesObj, responseCookiesObj);
+ await this.actions.updateRequest(id, payload, true);
+ }
+
+ async fetchImage(mimeType, responseContent) {
+ let payload = {};
+ if (mimeType && responseContent && responseContent.content) {
+ let { encoding, text } = responseContent.content;
+ let response = await this.getLongString(text);
+
+ if (mimeType.includes("image/")) {
+ payload.responseContentDataUri = formDataURI(mimeType, encoding, response);
+ }
+
+ responseContent.content.text = response;
+ payload.responseContent = responseContent;
+ }
+ return payload;
+ }
+
+ async fetchRequestHeaders(requestHeaders) {
+ let payload = {};
+ if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
+ let headers = await fetchHeaders(requestHeaders, this.getLongString);
+ if (headers) {
+ payload.requestHeaders = headers;
+ }
+ }
+ return payload;
+ }
+
+ async fetchResponseHeaders(responseHeaders) {
+ let payload = {};
+ if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) {
+ let headers = await fetchHeaders(responseHeaders, this.getLongString);
+ if (headers) {
+ payload.responseHeaders = headers;
+ }
+ }
+ return payload;
+ }
+
+ async fetchPostData(requestPostData) {
+ let payload = {};
+ if (requestPostData && requestPostData.postData) {
+ let { text } = requestPostData.postData;
+ let postData = await this.getLongString(text);
+ const headers = CurlUtils.getHeadersFromMultipartText(postData);
+ const headersSize = headers.reduce((acc, { name, value }) => {
+ return acc + name.length + value.length + 2;
+ }, 0);
+ requestPostData.postData.text = postData;
+ payload.requestPostData = Object.assign({}, requestPostData);
+ payload.requestHeadersFromUploadStream = { headers, headersSize };
+ }
+ return payload;
+ }
+
+ async fetchResponseCookies(responseCookies) {
+ let payload = {};
+ if (responseCookies) {
+ let resCookies = [];
+ // response store cookies in responseCookies or responseCookies.cookies
+ let cookies = responseCookies.cookies ?
+ responseCookies.cookies : responseCookies;
+ // make sure cookies is iterable
+ if (typeof cookies[Symbol.iterator] === "function") {
+ for (let cookie of cookies) {
+ resCookies.push(Object.assign({}, cookie, {
+ value: await this.getLongString(cookie.value),
+ }));
+ }
+ if (resCookies.length) {
+ payload.responseCookies = resCookies;
+ }
+ }
+ }
+ return payload;
+ }
+
+ async fetchRequestCookies(requestCookies) {
+ let payload = {};
+ if (requestCookies) {
+ let reqCookies = [];
+ // request store cookies in requestCookies or requestCookies.cookies
+ let cookies = requestCookies.cookies ?
+ requestCookies.cookies : requestCookies;
+ // make sure cookies is iterable
+ if (typeof cookies[Symbol.iterator] === "function") {
+ for (let cookie of cookies) {
+ reqCookies.push(Object.assign({}, cookie, {
+ value: await this.getLongString(cookie.value),
+ }));
+ }
+ if (reqCookies.length) {
+ payload.requestCookies = reqCookies;
+ }
+ }
+ }
+ return payload;
+ }
+
+ /**
+ * Access a payload item from payload queue.
+ *
+ * @param {string} id request id
+ * @return {boolean} return a queued payload item from queue.
+ */
+ getPayloadFromQueue(id) {
+ return this.payloadQueue.find((item) => item.id === id);
+ }
+
+ /**
+ * Packet order of "networkUpdateEvent" is predictable, as a result we can wait for
+ * the last one "eventTimings" packet arrives to check payload is ready.
+ *
+ * @param {string} id request id
+ * @return {boolean} return whether a specific networkEvent has been updated completely.
+ */
+ isQueuePayloadReady(id) {
+ let queuedPayload = this.getPayloadFromQueue(id);
+ return queuedPayload && queuedPayload.payload.eventTimings;
+ }
+
+ /**
+ * Push a request payload into a queue if request doesn't exist. Otherwise update the
+ * request itself.
+ *
+ * @param {string} id request id
+ * @param {object} payload request data payload
+ */
+ pushPayloadToQueue(id, payload) {
+ let queuedPayload = this.getPayloadFromQueue(id);
+ if (!queuedPayload) {
+ this.payloadQueue.push({ id, payload });
+ } else {
+ // Merge upcoming networkEventUpdate payload into existing one
+ queuedPayload.payload = Object.assign({}, queuedPayload.payload, payload);
+ }
+ }
+
+ /**
+ * Send a HTTP request data payload
+ *
+ * @param {object} data data payload would like to sent to backend
+ * @param {function} callback callback will be invoked after the request finished
+ */
+ sendHTTPRequest(data, callback) {
+ this.webConsoleClient.sendHTTPRequest(data, callback);
+ }
+
+ /**
+ * Set network preferences to control network flow
+ *
+ * @param {object} request request payload would like to sent to backend
+ * @param {function} callback callback will be invoked after the request finished
+ */
+ setPreferences(request, callback) {
+ this.webConsoleClient.setPreferences(request, callback);
+ }
+
+ /**
+ * Triggers a specific "activity" to be performed by the frontend.
+ * This can be, for example, triggering reloads or enabling/disabling cache.
+ *
+ * @param {number} type 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(type) {
+ // 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 = () => {
+ return new Promise((resolve) => {
+ this.tabTarget.once("will-navigate", () => {
+ this.tabTarget.once("navigate", () => {
+ resolve();
+ });
+ });
+ });
+ };
+
+ // Reconfigures the tab, optionally triggering a reload.
+ let reconfigureTab = (options) => {
+ return new Promise((resolve) => {
+ this.tabTarget.activeTab.reconfigure(options, resolve);
+ });
+ };
+
+ // Reconfigures the tab and waits for the target to finish navigating.
+ let reconfigureTabAndWaitForNavigation = (options) => {
+ options.performReload = true;
+ let navigationFinished = waitForNavigation();
+ return reconfigureTab(options).then(() => navigationFinished);
+ };
+ switch (type) {
+ case ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT:
+ return reconfigureTabAndWaitForNavigation({}).then(standBy);
+ case ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED:
+ this.currentActivity = ACTIVITY_TYPE.ENABLE_CACHE;
+ this.tabTarget.once("will-navigate", () => {
+ this.currentActivity = type;
+ });
+ return reconfigureTabAndWaitForNavigation({
+ cacheDisabled: false,
+ performReload: true,
+ }).then(standBy);
+ case ACTIVITY_TYPE.RELOAD.WITH_CACHE_DISABLED:
+ this.currentActivity = ACTIVITY_TYPE.DISABLE_CACHE;
+ this.tabTarget.once("will-navigate", () => {
+ this.currentActivity = type;
+ });
+ return reconfigureTabAndWaitForNavigation({
+ cacheDisabled: true,
+ performReload: true,
+ }).then(standBy);
+ case ACTIVITY_TYPE.ENABLE_CACHE:
+ this.currentActivity = type;
+ return reconfigureTab({
+ cacheDisabled: false,
+ performReload: false,
+ }).then(standBy);
+ case ACTIVITY_TYPE.DISABLE_CACHE:
+ this.currentActivity = type;
+ return reconfigureTab({
+ cacheDisabled: true,
+ performReload: false,
+ }).then(standBy);
+ }
+ this.currentActivity = ACTIVITY_TYPE.NONE;
+ return Promise.reject(new Error("Invalid activity type"));
+ }
+
+ /**
+ * Selects the specified request in the waterfall and opens the details view.
+ *
+ * @param {string} requestId The actor ID of the request to inspect.
+ * @return {object} A promise resolved once the task finishes.
+ */
+ inspectRequest(requestId) {
+ // Look for the request in the existing ones or wait for it to appear, if
+ // the network monitor is still loading.
+ return new Promise((resolve) => {
+ let request = null;
+ let inspector = () => {
+ request = getDisplayedRequestById(this.getState(), requestId);
+ if (!request) {
+ // Reset filters so that the request is visible.
+ this.actions.toggleRequestFilterType("all");
+ request = getDisplayedRequestById(this.getState(), requestId);
+ }
+
+ // If the request was found, select it. Otherwise this function will be
+ // called again once new requests arrive.
+ if (request) {
+ window.off(EVENTS.REQUEST_ADDED, inspector);
+ this.actions.selectRequest(request.id);
+ resolve();
+ }
+ };
+
+ inspector();
+
+ if (!request) {
+ window.on(EVENTS.REQUEST_ADDED, inspector);
+ }
+ });
+ }
+
+ /**
+ * Fetches the network information packet from actor server
+ *
+ * @param {string} id request id
+ * @return {object} networkInfo data packet
+ */
+ getNetworkRequest(id) {
+ return this.webConsoleClient.getNetworkRequest(id);
+ }
+
+ /**
+ * Fetches the full text of a LongString.
+ *
+ * @param {object|string} stringGrip
+ * 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}
+ * A promise that is resolved when the full string contents
+ * are available, or rejected if something goes wrong.
+ */
+ getLongString(stringGrip) {
+ return this.webConsoleClient.getString(stringGrip);
+ }
+
+ /**
+ * Getter that access tab target instance.
+ * @return {object} browser tab target instance
+ */
+ getTabTarget() {
+ return this.tabTarget;
+ }
+
+ /**
+ * Open a given source in Debugger
+ * @param {string} sourceURL source url
+ * @param {number} sourceLine source line number
+ */
+ viewSourceInDebugger(sourceURL, sourceLine) {
+ if (this.toolbox) {
+ this.toolbox.viewSourceInDebugger(sourceURL, sourceLine);
+ }
+ }
+
+ /**
+ * The "networkEvent" message type handler.
+ *
+ * @param {string} type message type
+ * @param {object} networkInfo network request information
+ */
+ onNetworkEvent(type, networkInfo) {
+ let {
+ actor,
+ cause,
+ fromCache,
+ fromServiceWorker,
+ isXHR,
+ request: {
+ method,
+ url,
+ },
+ startedDateTime,
+ } = networkInfo;
+
+ this.addRequest(actor, {
+ cause,
+ fromCache,
+ fromServiceWorker,
+ isXHR,
+ method,
+ startedDateTime,
+ url,
+ });
+
+ window.emit(EVENTS.NETWORK_EVENT, actor);
+ }
+
+ /**
+ * The "networkEventUpdate" message type handler.
+ *
+ * @param {string} type message type
+ * @param {object} packet the message received from the server.
+ * @param {object} networkInfo the network request information.
+ */
+ onNetworkEventUpdate(type, { packet, networkInfo }) {
+ let { actor } = networkInfo;
+
+ switch (packet.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":
+ this.updateRequest(actor, {
+ securityState: networkInfo.securityInfo,
+ }).then(() => {
+ 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":
+ this.updateRequest(actor, {
+ httpVersion: networkInfo.response.httpVersion,
+ remoteAddress: networkInfo.response.remoteAddress,
+ remotePort: networkInfo.response.remotePort,
+ status: networkInfo.response.status,
+ statusText: networkInfo.response.statusText,
+ headersSize: networkInfo.response.headersSize
+ }).then(() => {
+ window.emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor);
+ });
+ break;
+ case "responseContent":
+ this.webConsoleClient.getResponseContent(actor,
+ this.onResponseContent.bind(this, {
+ contentSize: networkInfo.response.bodySize,
+ transferredSize: networkInfo.response.transferredSize,
+ mimeType: networkInfo.response.content.mimeType
+ }));
+ window.emit(EVENTS.UPDATING_RESPONSE_CONTENT, actor);
+ break;
+ case "eventTimings":
+ this.updateRequest(actor, { totalTime: networkInfo.totalTime })
+ .then(() => {
+ this.webConsoleClient.getEventTimings(actor, this.onEventTimings);
+ window.emit(EVENTS.UPDATING_EVENT_TIMINGS, actor);
+ });
+ break;
+ }
+ }
+
+ /**
+ * Handles additional information received for a "requestHeaders" packet.
+ *
+ * @param {object} response the message received from the server.
+ */
+ onRequestHeaders(response) {
+ this.updateRequest(response.from, {
+ requestHeaders: response
+ }).then(() => {
+ window.emit(EVENTS.RECEIVED_REQUEST_HEADERS, response.from);
+ });
+ }
+
+ /**
+ * Handles additional information received for a "requestCookies" packet.
+ *
+ * @param {object} response the message received from the server.
+ */
+ onRequestCookies(response) {
+ this.updateRequest(response.from, {
+ requestCookies: response
+ }).then(() => {
+ window.emit(EVENTS.RECEIVED_REQUEST_COOKIES, response.from);
+ });
+ }
+
+ /**
+ * Handles additional information received for a "requestPostData" packet.
+ *
+ * @param {object} response the message received from the server.
+ */
+ onRequestPostData(response) {
+ this.updateRequest(response.from, {
+ requestPostData: response
+ }).then(() => {
+ window.emit(EVENTS.RECEIVED_REQUEST_POST_DATA, response.from);
+ });
+ }
+
+ /**
+ * Handles additional information received for a "securityInfo" packet.
+ *
+ * @param {object} response the message received from the server.
+ */
+ onSecurityInfo(response) {
+ this.updateRequest(response.from, {
+ securityInfo: response.securityInfo
+ }).then(() => {
+ window.emit(EVENTS.RECEIVED_SECURITY_INFO, response.from);
+ });
+ }
+
+ /**
+ * Handles additional information received for a "responseHeaders" packet.
+ *
+ * @param {object} response the message received from the server.
+ */
+ onResponseHeaders(response) {
+ this.updateRequest(response.from, {
+ responseHeaders: response
+ }).then(() => {
+ window.emit(EVENTS.RECEIVED_RESPONSE_HEADERS, response.from);
+ });
+ }
+
+ /**
+ * Handles additional information received for a "responseCookies" packet.
+ *
+ * @param {object} response the message received from the server.
+ */
+ onResponseCookies(response) {
+ this.updateRequest(response.from, {
+ responseCookies: response
+ }).then(() => {
+ window.emit(EVENTS.RECEIVED_RESPONSE_COOKIES, response.from);
+ });
+ }
+
+ /**
+ * Handles additional information received for a "responseContent" packet.
+ *
+ * @param {object} data the message received from the server event.
+ * @param {object} response the message received from the server.
+ */
+ onResponseContent(data, response) {
+ let payload = Object.assign({ responseContent: response }, data);
+ this.updateRequest(response.from, payload).then(() => {
+ window.emit(EVENTS.RECEIVED_RESPONSE_CONTENT, response.from);
+ });
+ }
+
+ /**
+ * Handles additional information received for a "eventTimings" packet.
+ *
+ * @param {object} response the message received from the server.
+ */
+ onEventTimings(response) {
+ this.updateRequest(response.from, {
+ eventTimings: response
+ }).then(() => {
+ window.emit(EVENTS.RECEIVED_EVENT_TIMINGS, response.from);
+ });
+ }
+}
+
+module.exports = new FirefoxConnector();
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/src/connector/index.js
@@ -0,0 +1,85 @@
+/* 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";
+
+let connector = {};
+
+function onConnect(connection, actions, getState) {
+ if (!connection || !connection.tab) {
+ return;
+ }
+
+ let { clientType } = connection.tab;
+ switch (clientType) {
+ case "chrome":
+ onChromeConnect(connection, actions, getState);
+ break;
+ case "firefox":
+ onFirefoxConnect(connection, actions, getState);
+ break;
+ default:
+ throw Error(`Unknown client type - ${clientType}`);
+ }
+}
+
+function onDisconnect() {
+ connector && connector.disconnect();
+}
+
+function onChromeConnect(connection, actions, getState) {
+ // TODO: support chrome debugging protocol
+}
+
+function onFirefoxConnect(connection, actions, getState) {
+ connector = require("./firefox-connector");
+ connector.connect(connection, actions, getState);
+}
+
+function inspectRequest() {
+ return connector.inspectRequest(...arguments);
+}
+
+function getLongString() {
+ return connector.getLongString(...arguments);
+}
+
+function getNetworkRequest() {
+ return connector.getNetworkRequest(...arguments);
+}
+
+function getTabTarget() {
+ return connector.getTabTarget();
+}
+
+function sendHTTPRequest() {
+ return connector.sendHTTPRequest(...arguments);
+}
+
+function setPreferences() {
+ return connector.setPreferences(...arguments);
+}
+
+function triggerActivity() {
+ return connector.triggerActivity(...arguments);
+}
+
+function viewSourceInDebugger() {
+ return connector.viewSourceInDebugger();
+}
+
+module.exports = {
+ onConnect,
+ onChromeConnect,
+ onFirefoxConnect,
+ onDisconnect,
+ getLongString,
+ getNetworkRequest,
+ getTabTarget,
+ inspectRequest,
+ sendHTTPRequest,
+ setPreferences,
+ triggerActivity,
+ viewSourceInDebugger,
+};
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/src/connector/moz.build
@@ -0,0 +1,8 @@
+# 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/.
+
+DevToolsModules(
+ 'firefox-connector.js',
+ 'index.js',
+)
--- a/devtools/client/netmonitor/src/constants.js
+++ b/devtools/client/netmonitor/src/constants.js
@@ -42,20 +42,16 @@ const ACTIVITY_TYPE = {
// Enabling or disabling the cache without triggering a reload.
ENABLE_CACHE: 3,
DISABLE_CACHE: 4
};
// 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 or timeline 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",
TIMELINE_EVENT: "NetMonitor:TimelineEvent",
// When a network event is added to the view
REQUEST_ADDED: "NetMonitor:RequestAdded",
@@ -88,18 +84,17 @@ const EVENTS = {
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",
- // Fired once the NetMonitorController establishes a connection to the debug
- // target.
+ // Fired once the connection is established
CONNECTED: "connected",
};
const HEADERS = [
{
name: "status",
label: "status3",
canFilter: true,
--- a/devtools/client/netmonitor/src/har/har-builder.js
+++ b/devtools/client/netmonitor/src/har/har-builder.js
@@ -3,17 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Services = require("Services");
const appInfo = Services.appinfo;
const { LocalizationHelper } = require("devtools/shared/l10n");
const { CurlUtils } = require("devtools/client/shared/curl");
-const { getLongString } = require("../utils/client");
+const { getLongString } = require("../connector/index");
const {
getFormDataSections,
getUrlQuery,
parseQueryString,
} = require("../utils/request-utils");
const L10N = new LocalizationHelper("devtools/client/locales/har.properties");
const HAR_VERSION = "1.1";
--- a/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js
+++ b/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js
@@ -6,22 +6,21 @@
/**
* Basic tests for exporting Network panel content into HAR format.
*/
add_task(function* () {
let { tab, monitor } = yield initNetMonitor(SIMPLE_URL);
info("Starting test... ");
- let { gStore, windowRequire } = monitor.panelWin;
- let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+ let { actions, windowRequire } = monitor.panelWin;
let RequestListContextMenu = windowRequire(
"devtools/client/netmonitor/src/request-list-context-menu");
- gStore.dispatch(Actions.batchEnable(false));
+ actions.batchEnable(false);
let wait = waitForNetworkEvents(monitor, 1);
tab.linkedBrowser.reload();
yield wait;
let contextMenu = new RequestListContextMenu({});
yield contextMenu.copyAllAsHar();
--- a/devtools/client/netmonitor/src/har/test/browser_net_har_post_data.js
+++ b/devtools/client/netmonitor/src/har/test/browser_net_har_post_data.js
@@ -7,22 +7,21 @@
* Tests for exporting POST data into HAR format.
*/
add_task(function* () {
let { tab, monitor } = yield initNetMonitor(
HAR_EXAMPLE_URL + "html_har_post-data-test-page.html");
info("Starting test... ");
- let { gStore, windowRequire } = monitor.panelWin;
- let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+ let { actions, windowRequire } = monitor.panelWin;
let RequestListContextMenu = windowRequire(
"devtools/client/netmonitor/src/request-list-context-menu");
- gStore.dispatch(Actions.batchEnable(false));
+ actions.batchEnable(false);
// Execute one POST request on the page and wait till its done.
let wait = waitForNetworkEvents(monitor, 0, 1);
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.wrappedJSObject.executeTest();
});
yield wait;
--- a/devtools/client/netmonitor/src/har/test/browser_net_har_throttle_upload.js
+++ b/devtools/client/netmonitor/src/har/test/browser_net_har_throttle_upload.js
@@ -11,43 +11,41 @@ add_task(function* () {
});
function* throttleUploadTest(actuallyThrottle) {
let { tab, monitor } = yield initNetMonitor(
HAR_EXAMPLE_URL + "html_har_post-data-test-page.html");
info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")");
- let { gStore, windowRequire } = monitor.panelWin;
- let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
- let { NetMonitorController } =
- windowRequire("devtools/client/netmonitor/src/netmonitor-controller");
+ let { actions, windowRequire } = monitor.panelWin;
+ let { setPreferences } =
+ windowRequire("devtools/client/netmonitor/src/connector/index");
let RequestListContextMenu = windowRequire(
"devtools/client/netmonitor/src/request-list-context-menu");
- gStore.dispatch(Actions.batchEnable(false));
+ actions.batchEnable(false);
const size = 4096;
const uploadSize = actuallyThrottle ? size / 3 : 0;
const request = {
"NetworkMonitor.throttleData": {
latencyMean: 0,
latencyMax: 0,
downloadBPSMean: 200000,
downloadBPSMax: 200000,
uploadBPSMean: uploadSize,
uploadBPSMax: uploadSize,
},
};
- let client = NetMonitorController.webConsoleClient;
info("sending throttle request");
yield new Promise((resolve) => {
- client.setPreferences(request, response => {
+ setPreferences(request, (response) => {
resolve(response);
});
});
// Execute one POST request on the page and wait till its done.
let wait = waitForNetworkEvents(monitor, 0, 1);
yield ContentTask.spawn(tab.linkedBrowser, { size }, function* (args) {
content.wrappedJSObject.executeTest2(args.size);
--- a/devtools/client/netmonitor/src/moz.build
+++ b/devtools/client/netmonitor/src/moz.build
@@ -1,22 +1,22 @@
# 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/.
DIRS += [
'actions',
'components',
+ 'connector',
'har',
'middleware',
'reducers',
'selectors',
'utils',
]
DevToolsModules(
'constants.js',
- 'netmonitor-controller.js',
'request-list-context-menu.js',
'request-list-header-context-menu.js',
'request-list-tooltip.js',
'waterfall-background.js',
)
deleted file mode 100644
--- a/devtools/client/netmonitor/src/netmonitor-controller.js
+++ /dev/null
@@ -1,781 +0,0 @@
-/* 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 { TimelineFront } = require("devtools/shared/fronts/timeline");
-const { CurlUtils } = require("devtools/client/shared/curl");
-const { ACTIVITY_TYPE, EVENTS } = require("./constants");
-const { getDisplayedRequestById } = require("./selectors/index");
-const {
- fetchHeaders,
- formDataURI,
-} = require("./utils/request-utils");
-const {
- getLongString,
- getWebConsoleClient,
- onFirefoxConnect,
- onFirefoxDisconnect,
-} = require("./utils/client");
-
-/**
- * Object defining the network monitor controller components.
- */
-var NetMonitorController = {
- /**
- * Initializes the view and connects the monitor client.
- *
- * @param {Object} connection connection data wrapper
- * @return {Object} A promise that is resolved when the monitor finishes startup.
- */
- startupNetMonitor(connection, actions) {
- if (this._startup) {
- return this._startup;
- }
- this.actions = actions;
- this._startup = new Promise(async (resolve) => {
- await this.connect(connection);
- resolve();
- });
- return this._startup;
- },
-
- /**
- * Destroys the view and disconnects the monitor client from the server.
- *
- * @return object
- * A promise that is resolved when the monitor finishes shutdown.
- */
- shutdownNetMonitor() {
- if (this._shutdown) {
- return this._shutdown;
- }
- this._shutdown = new Promise(async (resolve) => {
- this.actions.batchReset();
- onFirefoxDisconnect(this._target);
- this._target.off("close", this._onTabDetached);
- this.NetworkEventsHandler.disconnect();
- await this.disconnect();
- resolve();
- });
-
- return this._shutdown;
- },
-
- /**
- * Initiates remote or chrome network monitoring based on the current target,
- * wiring event handlers as necessary. Since the TabTarget will have already
- * started listening to network requests by now, this is largely
- * netmonitor-specific initialization.
- *
- * @param {Object} connection connection data wrapper
- * @return {Object} A promise that is resolved when the monitor finishes connecting.
- */
- connect(connection) {
- if (this._connection) {
- return this._connection;
- }
- this._onTabDetached = this.shutdownNetMonitor.bind(this);
-
- this._connection = new Promise(async (resolve) => {
- // Some actors like AddonActor or RootActor for chrome debugging
- // aren't actual tabs.
- this.toolbox = connection.toolbox;
- this._target = connection.tabConnection.tabTarget;
- this.tabClient = this._target.isTabActor ? this._target.activeTab : null;
-
- let connectTimeline = () => {
- // Don't start up waiting for timeline markers if the server isn't
- // recent enough to emit the markers we're interested in.
- if (this._target.getTrait("documentLoadingMarkers")) {
- this.timelineFront = new TimelineFront(this._target.client,
- this._target.form);
- return this.timelineFront.start({ withDocLoadingEvents: true });
- }
- return undefined;
- };
- await connectTimeline();
-
- onFirefoxConnect(this._target);
- this._target.on("close", this._onTabDetached);
-
- this.webConsoleClient = getWebConsoleClient();
- this.NetworkEventsHandler = new NetworkEventsHandler();
- this.NetworkEventsHandler.connect(this.actions);
-
- window.emit(EVENTS.CONNECTED);
-
- resolve();
- this._connected = true;
- });
- return this._connection;
- },
-
- /**
- * Disconnects the debugger client and removes event handlers as necessary.
- */
- disconnect() {
- if (this._disconnection) {
- return this._disconnection;
- }
- this._disconnection = new Promise(async (resolve) => {
- // Wait for the connection to finish first.
- if (!this._connected) {
- await this._connection;
- }
-
- // When debugging local or a remote instance, the connection is closed by
- // the RemoteTarget. The webconsole actor is stopped on disconnect.
- this.tabClient = null;
- this.webConsoleClient = null;
-
- // The timeline front wasn't initialized and started if the server wasn't
- // recent enough to emit the markers we were interested in.
- if (this._target.getTrait("documentLoadingMarkers")) {
- await this.timelineFront.destroy();
- this.timelineFront = null;
- }
-
- resolve();
- this._connected = false;
- });
- return this._disconnection;
- },
-
- /**
- * Triggers a specific "activity" to be performed by the frontend.
- * This can be, for example, triggering reloads or enabling/disabling cache.
- *
- * @param number type
- * 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 (type) {
- // 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 = () => {
- return new Promise((resolve) => {
- this._target.once("will-navigate", () => {
- this._target.once("navigate", () => {
- resolve();
- });
- });
- });
- };
-
- // Reconfigures the tab, optionally triggering a reload.
- let reconfigureTab = options => {
- return new Promise((resolve) => {
- this._target.activeTab.reconfigure(options, resolve);
- });
- };
-
- // Reconfigures the tab and waits for the target to finish navigating.
- let reconfigureTabAndWaitForNavigation = options => {
- options.performReload = true;
- let navigationFinished = waitForNavigation();
- return reconfigureTab(options).then(() => navigationFinished);
- };
- if (type == ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT) {
- return reconfigureTabAndWaitForNavigation({}).then(standBy);
- }
- if (type == ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED) {
- this._currentActivity = ACTIVITY_TYPE.ENABLE_CACHE;
- this._target.once("will-navigate", () => {
- this._currentActivity = type;
- });
- return reconfigureTabAndWaitForNavigation({
- cacheDisabled: false,
- performReload: true
- }).then(standBy);
- }
- if (type == ACTIVITY_TYPE.RELOAD.WITH_CACHE_DISABLED) {
- this._currentActivity = ACTIVITY_TYPE.DISABLE_CACHE;
- this._target.once("will-navigate", () => {
- this._currentActivity = type;
- });
- return reconfigureTabAndWaitForNavigation({
- cacheDisabled: true,
- performReload: true
- }).then(standBy);
- }
- if (type == ACTIVITY_TYPE.ENABLE_CACHE) {
- this._currentActivity = type;
- return reconfigureTab({
- cacheDisabled: false,
- performReload: false
- }).then(standBy);
- }
- if (type == ACTIVITY_TYPE.DISABLE_CACHE) {
- this._currentActivity = type;
- return reconfigureTab({
- cacheDisabled: true,
- performReload: false
- }).then(standBy);
- }
- this._currentActivity = ACTIVITY_TYPE.NONE;
- return Promise.reject(new Error("Invalid activity type"));
- },
-
- /**
- * Selects the specified request in the waterfall and opens the details view.
- *
- * @param string requestId
- * The actor ID of the request to inspect.
- * @return object
- * A promise resolved once the task finishes.
- */
- inspectRequest(requestId) {
- // Look for the request in the existing ones or wait for it to appear, if
- // the network monitor is still loading.
- return new Promise((resolve) => {
- let request = null;
- let inspector = () => {
- request = getDisplayedRequestById(window.gStore.getState(), requestId);
- if (!request) {
- // Reset filters so that the request is visible.
- this.actions.toggleRequestFilterType("all");
- request = getDisplayedRequestById(window.gStore.getState(), requestId);
- }
-
- // If the request was found, select it. Otherwise this function will be
- // called again once new requests arrive.
- if (request) {
- window.off(EVENTS.REQUEST_ADDED, inspector);
- this.actions.selectRequest(request.id);
- resolve();
- }
- };
-
- inspector();
- if (!request) {
- window.on(EVENTS.REQUEST_ADDED, inspector);
- }
- });
- },
-
- /**
- * 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 can do network performance statistics.
- * @type boolean
- */
- get supportsPerfStats() {
- return this.tabClient &&
- (this.tabClient.traits.reconfigure || !this._target.isApp);
- },
-
- /**
- * Open a given source in Debugger
- */
- viewSourceInDebugger(sourceURL, sourceLine) {
- if (this.toolbox) {
- this.toolbox.viewSourceInDebugger(sourceURL, sourceLine);
- }
- },
-};
-
-/**
- * Functions handling target network events.
- */
-function NetworkEventsHandler() {
- this.payloadQueue = [];
- this.addRequest = this.addRequest.bind(this);
- this.updateRequest = this.updateRequest.bind(this);
- this._onNetworkEvent = this._onNetworkEvent.bind(this);
- this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
- this._onDocLoadingMarker = this._onDocLoadingMarker.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._onSecurityInfo = this._onSecurityInfo.bind(this);
- this._onEventTimings = this._onEventTimings.bind(this);
-}
-
-NetworkEventsHandler.prototype = {
- get client() {
- return NetMonitorController._target.client;
- },
-
- get webConsoleClient() {
- return NetMonitorController.webConsoleClient;
- },
-
- get timelineFront() {
- return NetMonitorController.timelineFront;
- },
-
- /**
- * Connect to the current target client.
- */
- connect(actions) {
- this.actions = actions;
- this.webConsoleClient.on("networkEvent", this._onNetworkEvent);
- this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate);
-
- if (this.timelineFront) {
- this.timelineFront.on("doc-loading", this._onDocLoadingMarker);
- }
-
- this._displayCachedEvents();
- },
-
- /**
- * Disconnect from the client.
- */
- disconnect() {
- if (!this.client) {
- return;
- }
- this.webConsoleClient.off("networkEvent", this._onNetworkEvent);
- this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate);
-
- if (this.timelineFront) {
- this.timelineFront.off("doc-loading", this._onDocLoadingMarker);
- }
- },
-
- /**
- * Display any network events already in the cache.
- */
- _displayCachedEvents: function () {
- for (let cachedEvent of this.webConsoleClient.getNetworkEvents()) {
- // First add the request to the timeline.
- this._onNetworkEvent("networkEvent", cachedEvent);
- // Then replay any updates already received.
- for (let update of cachedEvent.updates) {
- this._onNetworkEventUpdate("networkEventUpdate", {
- packet: {
- updateType: update
- },
- networkInfo: cachedEvent
- });
- }
- }
- },
-
- /**
- * The "DOMContentLoaded" and "Load" events sent by the timeline actor.
- * @param object marker
- */
- _onDocLoadingMarker: function (marker) {
- this.actions.addTimingMarker(marker);
- window.emit(EVENTS.TIMELINE_EVENT, marker);
- },
-
- /**
- * The "networkEvent" message type handler.
- *
- * @param string type
- * Message type.
- * @param object networkInfo
- * The network request information.
- */
- _onNetworkEvent: function (type, networkInfo) {
- let { actor,
- startedDateTime,
- request: { method, url },
- isXHR,
- cause,
- fromCache,
- fromServiceWorker
- } = networkInfo;
-
- this.addRequest(
- actor, {startedDateTime, method, url, isXHR, cause, fromCache, fromServiceWorker}
- );
- window.emit(EVENTS.NETWORK_EVENT, actor);
- },
-
- addRequest(id, data) {
- let { method, url, isXHR, cause, startedDateTime, fromCache,
- fromServiceWorker } = data;
-
- this.actions.addRequest(
- id,
- {
- // Convert the received date/time string to a unix timestamp.
- startedMillis: Date.parse(startedDateTime),
- method,
- url,
- isXHR,
- cause,
- fromCache,
- fromServiceWorker,
- },
- true
- )
- .then(() => window.emit(EVENTS.REQUEST_ADDED, id));
- },
-
- async fetchImage(mimeType, responseContent) {
- let payload = {};
- if (mimeType && responseContent && responseContent.content) {
- let { encoding, text } = responseContent.content;
- let response = await getLongString(text);
-
- if (mimeType.includes("image/")) {
- payload.responseContentDataUri = formDataURI(mimeType, encoding, response);
- }
-
- responseContent.content.text = response;
- payload.responseContent = responseContent;
- }
- return payload;
- },
-
- async fetchRequestHeaders(requestHeaders) {
- let payload = {};
- if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
- let headers = await fetchHeaders(requestHeaders, getLongString);
- if (headers) {
- payload.requestHeaders = headers;
- }
- }
- return payload;
- },
-
- async fetchResponseHeaders(responseHeaders) {
- let payload = {};
- if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) {
- let headers = await fetchHeaders(responseHeaders, getLongString);
- if (headers) {
- payload.responseHeaders = headers;
- }
- }
- return payload;
- },
-
- // Search the POST data upload stream for request headers and add
- // them as a separate property, different from the classic headers.
- async fetchPostData(requestPostData) {
- let payload = {};
- if (requestPostData && requestPostData.postData) {
- let { text } = requestPostData.postData;
- let postData = await getLongString(text);
- const headers = CurlUtils.getHeadersFromMultipartText(postData);
- const headersSize = headers.reduce((acc, { name, value }) => {
- return acc + name.length + value.length + 2;
- }, 0);
- requestPostData.postData.text = postData;
- payload.requestPostData = Object.assign({}, requestPostData);
- payload.requestHeadersFromUploadStream = { headers, headersSize };
- }
- return payload;
- },
-
- async fetchResponseCookies(responseCookies) {
- let payload = {};
- if (responseCookies) {
- let resCookies = [];
- // response store cookies in responseCookies or responseCookies.cookies
- let cookies = responseCookies.cookies ?
- responseCookies.cookies : responseCookies;
- // make sure cookies is iterable
- if (typeof cookies[Symbol.iterator] === "function") {
- for (let cookie of cookies) {
- resCookies.push(Object.assign({}, cookie, {
- value: await getLongString(cookie.value),
- }));
- }
- if (resCookies.length) {
- payload.responseCookies = resCookies;
- }
- }
- }
- return payload;
- },
-
- // Fetch request and response cookies long value.
- // Actor does not provide full sized cookie value when the value is too long
- // To display values correctly, we need fetch them in each request.
- async fetchRequestCookies(requestCookies) {
- let payload = {};
- if (requestCookies) {
- let reqCookies = [];
- // request store cookies in requestCookies or requestCookies.cookies
- let cookies = requestCookies.cookies ?
- requestCookies.cookies : requestCookies;
- // make sure cookies is iterable
- if (typeof cookies[Symbol.iterator] === "function") {
- for (let cookie of cookies) {
- reqCookies.push(Object.assign({}, cookie, {
- value: await getLongString(cookie.value),
- }));
- }
- if (reqCookies.length) {
- payload.requestCookies = reqCookies;
- }
- }
- }
- return payload;
- },
-
- getPayloadFromQueue(id) {
- return this.payloadQueue.find((item) => item.id === id);
- },
-
- // Packet order of "networkUpdateEvent" is predictable, as a result we can wait for
- // the last one "eventTimings" packet arrives to check payload is ready
- isQueuePayloadReady(id) {
- let queuedPayload = this.getPayloadFromQueue(id);
- return queuedPayload && queuedPayload.payload.eventTimings;
- },
-
- pushPayloadToQueue(id, payload) {
- let queuedPayload = this.getPayloadFromQueue(id);
- if (!queuedPayload) {
- this.payloadQueue.push({ id, payload });
- } else {
- // Merge upcoming networkEventUpdate payload into existing one
- queuedPayload.payload = Object.assign({}, queuedPayload.payload, payload);
- }
- },
-
- async updateRequest(id, data) {
- let {
- mimeType,
- responseContent,
- responseCookies,
- responseHeaders,
- requestCookies,
- requestHeaders,
- requestPostData,
- } = data;
-
- // fetch request detail contents in parallel
- let [
- imageObj,
- requestHeadersObj,
- responseHeadersObj,
- postDataObj,
- requestCookiesObj,
- responseCookiesObj,
- ] = await Promise.all([
- this.fetchImage(mimeType, responseContent),
- this.fetchRequestHeaders(requestHeaders),
- this.fetchResponseHeaders(responseHeaders),
- this.fetchPostData(requestPostData),
- this.fetchRequestCookies(requestCookies),
- this.fetchResponseCookies(responseCookies),
- ]);
-
- let payload = Object.assign({}, data,
- imageObj, requestHeadersObj, responseHeadersObj,
- postDataObj, requestCookiesObj, responseCookiesObj);
-
- this.pushPayloadToQueue(id, payload);
-
- if (this.isQueuePayloadReady(id)) {
- await this.actions.updateRequest(id, this.getPayloadFromQueue(id).payload, true);
- }
- },
-
- /**
- * The "networkEventUpdate" message type handler.
- *
- * @param string type
- * Message type.
- * @param object packet
- * The message received from the server.
- * @param object networkInfo
- * The network request information.
- */
- _onNetworkEventUpdate: function (type, { packet, networkInfo }) {
- let { actor } = networkInfo;
- switch (packet.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":
- this.updateRequest(actor, {
- securityState: networkInfo.securityInfo,
- }).then(() => {
- 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":
- this.updateRequest(actor, {
- httpVersion: networkInfo.response.httpVersion,
- remoteAddress: networkInfo.response.remoteAddress,
- remotePort: networkInfo.response.remotePort,
- status: networkInfo.response.status,
- statusText: networkInfo.response.statusText,
- headersSize: networkInfo.response.headersSize
- }).then(() => {
- window.emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor);
- });
- break;
- case "responseContent":
- this.webConsoleClient.getResponseContent(actor,
- this._onResponseContent.bind(this, {
- contentSize: networkInfo.response.bodySize,
- transferredSize: networkInfo.response.transferredSize,
- mimeType: networkInfo.response.content.mimeType
- }));
- window.emit(EVENTS.UPDATING_RESPONSE_CONTENT, actor);
- break;
- case "eventTimings":
- this.updateRequest(actor, {
- totalTime: networkInfo.totalTime
- }).then(() => {
- this.webConsoleClient.getEventTimings(actor, this._onEventTimings);
- window.emit(EVENTS.UPDATING_EVENT_TIMINGS, actor);
- });
- break;
- }
- },
-
- /**
- * Handles additional information received for a "requestHeaders" packet.
- *
- * @param object response
- * The message received from the server.
- */
- _onRequestHeaders: function (response) {
- this.updateRequest(response.from, {
- requestHeaders: response
- }).then(() => {
- window.emit(EVENTS.RECEIVED_REQUEST_HEADERS, response.from);
- });
- },
-
- /**
- * Handles additional information received for a "requestCookies" packet.
- *
- * @param object response
- * The message received from the server.
- */
- _onRequestCookies: function (response) {
- this.updateRequest(response.from, {
- requestCookies: response
- }).then(() => {
- window.emit(EVENTS.RECEIVED_REQUEST_COOKIES, response.from);
- });
- },
-
- /**
- * Handles additional information received for a "requestPostData" packet.
- *
- * @param object response
- * The message received from the server.
- */
- _onRequestPostData: function (response) {
- this.updateRequest(response.from, {
- requestPostData: response
- }).then(() => {
- window.emit(EVENTS.RECEIVED_REQUEST_POST_DATA, response.from);
- });
- },
-
- /**
- * Handles additional information received for a "securityInfo" packet.
- *
- * @param object response
- * The message received from the server.
- */
- _onSecurityInfo: function (response) {
- this.updateRequest(response.from, {
- securityInfo: response.securityInfo
- }).then(() => {
- window.emit(EVENTS.RECEIVED_SECURITY_INFO, response.from);
- });
- },
-
- /**
- * Handles additional information received for a "responseHeaders" packet.
- *
- * @param object response
- * The message received from the server.
- */
- _onResponseHeaders: function (response) {
- this.updateRequest(response.from, {
- responseHeaders: response
- }).then(() => {
- window.emit(EVENTS.RECEIVED_RESPONSE_HEADERS, response.from);
- });
- },
-
- /**
- * Handles additional information received for a "responseCookies" packet.
- *
- * @param object response
- * The message received from the server.
- */
- _onResponseCookies: function (response) {
- this.updateRequest(response.from, {
- responseCookies: response
- }).then(() => {
- window.emit(EVENTS.RECEIVED_RESPONSE_COOKIES, response.from);
- });
- },
-
- /**
- * Handles additional information received for a "responseContent" packet.
- *
- * @param object data
- * The message received from the server event.
- * @param object response
- * The message received from the server.
- */
- _onResponseContent: function (data, response) {
- let payload = Object.assign({ responseContent: response }, data);
- this.updateRequest(response.from, payload).then(() => {
- window.emit(EVENTS.RECEIVED_RESPONSE_CONTENT, response.from);
- });
- },
-
- /**
- * Handles additional information received for a "eventTimings" packet.
- *
- * @param object response
- * The message received from the server.
- */
- _onEventTimings: function (response) {
- this.updateRequest(response.from, {
- eventTimings: response
- }).then(() => {
- window.emit(EVENTS.RECEIVED_EVENT_TIMINGS, response.from);
- });
- }
-};
-
-exports.NetMonitorController = NetMonitorController;
--- a/devtools/client/netmonitor/src/request-list-context-menu.js
+++ b/devtools/client/netmonitor/src/request-list-context-menu.js
@@ -5,22 +5,24 @@
"use strict";
const Services = require("Services");
const { Curl } = require("devtools/client/shared/curl");
const { gDevTools } = require("devtools/client/framework/devtools");
const { saveAs } = require("devtools/client/shared/file-saver");
const { copyString } = require("devtools/shared/platform/clipboard");
const { HarExporter } = require("./har/har-exporter");
-const { NetMonitorController } = require("./netmonitor-controller");
+const {
+ getLongString,
+ getTabTarget,
+} = require("./connector/index");
const {
getSelectedRequest,
getSortedRequests,
} = require("./selectors/index");
-const { getLongString } = require("./utils/client");
const { L10N } = require("./utils/l10n");
const { showMenu } = require("./utils/menu");
const {
getUrlQuery,
parseQueryString,
} = require("./utils/request-utils");
function RequestListContextMenu({
@@ -28,21 +30,25 @@ function RequestListContextMenu({
openStatistics,
}) {
this.cloneSelectedRequest = cloneSelectedRequest;
this.openStatistics = openStatistics;
}
RequestListContextMenu.prototype = {
get selectedRequest() {
- return getSelectedRequest(window.gStore.getState());
+ // FIXME: Bug 1336382 - Implement RequestListContextMenu React component
+ // Remove window.store
+ return getSelectedRequest(window.store.getState());
},
get sortedRequests() {
- return getSortedRequests(window.gStore.getState());
+ // FIXME: Bug 1336382 - Implement RequestListContextMenu React component
+ // Remove window.store
+ return getSortedRequests(window.store.getState());
},
/**
* Handle the context menu opening. Hide items if no request is selected.
* Since visible attribute only accept boolean value but the method call may
* return undefined, we use !! to force convert any object to boolean
*/
open(event = {}) {
@@ -159,26 +165,24 @@ RequestListContextMenu.prototype = {
visible: !!(selectedRequest &&
selectedRequest.responseContent &&
selectedRequest.responseContent.content.mimeType.includes("image/")),
click: () => this.saveImageAs(),
});
menu.push({
type: "separator",
- visible: !!(NetMonitorController.supportsCustomRequest &&
- selectedRequest && !selectedRequest.isCustom),
+ visible: !!(selectedRequest && !selectedRequest.isCustom),
});
menu.push({
id: "request-list-context-resend",
label: L10N.getStr("netmonitor.context.editAndResend"),
accesskey: L10N.getStr("netmonitor.context.editAndResend.accesskey"),
- visible: !!(NetMonitorController.supportsCustomRequest &&
- selectedRequest && !selectedRequest.isCustom),
+ visible: !!(selectedRequest && !selectedRequest.isCustom),
click: this.cloneSelectedRequest,
});
menu.push({
type: "separator",
visible: !!selectedRequest,
});
@@ -340,17 +344,17 @@ RequestListContextMenu.prototype = {
// FIXME: This will not work in launchpad
// document.execCommand(‘cut’/‘copy’) was denied because it was not called from
// inside a short running user-generated event handler.
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard
return HarExporter.save(this.getDefaultHarOptions());
},
getDefaultHarOptions() {
- let form = NetMonitorController._target.form;
+ let form = getTabTarget().form;
let title = form.title || form.url;
return {
getString: getLongString,
items: this.sortedRequests,
title: title
};
}
--- a/devtools/client/netmonitor/src/request-list-header-context-menu.js
+++ b/devtools/client/netmonitor/src/request-list-header-context-menu.js
@@ -14,17 +14,19 @@ const stringMap = HEADERS
class RequestListHeaderContextMenu {
constructor({ toggleColumn, resetColumns }) {
this.toggleColumn = toggleColumn;
this.resetColumns = resetColumns;
}
get columns() {
- return window.gStore.getState().ui.columns;
+ // FIXME: Bug 1362059 - Implement RequestListHeaderContextMenu React component
+ // Remove window.store
+ return window.store.getState().ui.columns;
}
get visibleColumns() {
return [...this.columns].filter(([_, shown]) => shown);
}
/**
* Handle the context menu opening.
--- a/devtools/client/netmonitor/src/request-list-tooltip.js
+++ b/devtools/client/netmonitor/src/request-list-tooltip.js
@@ -3,17 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
setImageTooltip,
getImageDimensions,
} = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
-const { getLongString } = require("./utils/client");
+const { getLongString } = require("./connector/index");
const { formDataURI } = require("./utils/request-utils");
const REQUESTS_TOOLTIP_IMAGE_MAX_DIM = 400; // px
async function setTooltipImageContent(tooltip, itemEl, requestItem) {
let { mimeType, text, encoding } = requestItem.responseContent.content;
if (!mimeType || !mimeType.includes("image/")) {
deleted file mode 100644
--- a/devtools/client/netmonitor/src/utils/client.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/* 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/. */
-
-/* global gStore */
-
-"use strict";
-
-const Services = require("Services");
-const Actions = require("../actions/index");
-const { EVENTS } = require("../constants");
-
-let activeConsole;
-
-/**
- * Called for each location change in the monitored tab.
- *
- * @param {String} type Packet type.
- * @param {Object} packet Packet received from the server.
- */
-function navigated(type) {
- window.emit(EVENTS.TARGET_DID_NAVIGATE);
-}
-
-/**
- * Called for each location change in the monitored tab.
- *
- * @param {String} type Packet type.
- * @param {Object} packet Packet received from the server.
- */
-function willNavigate(type) {
- // Reset UI.
- if (!Services.prefs.getBoolPref("devtools.webconsole.persistlog")) {
- gStore.dispatch(Actions.batchReset());
- gStore.dispatch(Actions.clearRequests());
- } else {
- // If the log is persistent, just clear all accumulated timing markers.
- gStore.dispatch(Actions.clearTimingMarkers());
- }
-
- window.emit(EVENTS.TARGET_WILL_NAVIGATE);
-}
-
-/**
- * Process connection events.
- *
- * @param {Object} tabTarget
- */
-function onFirefoxConnect(tabTarget) {
- activeConsole = tabTarget.activeConsole;
- tabTarget.on("navigate", navigated);
- tabTarget.on("will-navigate", willNavigate);
-}
-
-/**
- * Process disconnect events.
- *
- * @param {Object} tabTarget
- */
-function onFirefoxDisconnect(tabTarget) {
- activeConsole = null;
- tabTarget.off("navigate", navigated);
- tabTarget.off("will-navigate", willNavigate);
-}
-
-/**
- * Retrieve webconsole object
- *
- * @returns {Object} webConsole
- */
-function getWebConsoleClient() {
- return activeConsole;
-}
-
-/**
- * Fetches the full text of a LongString.
- *
- * @param object | string stringGrip
- * 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.
- */
-function getLongString(stringGrip) {
- // FIXME: this.webConsoleClient will be undefined in mochitest,
- // so we return string instantly to skip undefined error
- if (typeof stringGrip === "string") {
- return Promise.resolve(stringGrip);
- }
-
- return activeConsole.getString(stringGrip);
-}
-
-module.exports = {
- getLongString,
- getWebConsoleClient,
- onFirefoxConnect,
- onFirefoxDisconnect,
-};
--- a/devtools/client/netmonitor/src/utils/moz.build
+++ b/devtools/client/netmonitor/src/utils/moz.build
@@ -1,15 +1,14 @@
# vim: set filetype=python:
# 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/.
DevToolsModules(
- 'client.js',
'create-store.js',
'filter-predicates.js',
'filter-text-utils.js',
'format-utils.js',
'l10n.js',
'mdn-utils.js',
'menu.js',
'prefs.js',
--- a/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
+++ b/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
@@ -83,18 +83,20 @@ NewConsoleOutputWrapper.prototype = {
frame.url,
frame.line
),
onViewSourceInStyleEditor: frame => this.toolbox.viewSourceInStyleEditor(
frame.url,
frame.line
),
openNetworkPanel: (requestId) => {
- return this.toolbox.selectTool("netmonitor").then(panel => {
- return panel.panelWin.NetMonitorController.inspectRequest(requestId);
+ return this.toolbox.selectTool("netmonitor").then((panel) => {
+ let { inspectRequest } = panel.panelWin.windowRequire(
+ "devtools/client/netmonitor/src/connector/index");
+ return inspectRequest(requestId);
});
},
sourceMapService: this.toolbox ? this.toolbox.sourceMapURLService : null,
highlightDomElement: (grip, options = {}) => {
return this.toolbox.highlighterUtils
? this.toolbox.highlighterUtils.highlightDomValueGrip(grip, options)
: null;
},
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -1932,19 +1932,19 @@ WebConsoleFrame.prototype = {
*/
openNetworkPanel: function (requestId) {
let toolbox = gDevTools.getToolbox(this.owner.target);
// The browser console doesn't have a toolbox.
if (!toolbox) {
return;
}
return toolbox.selectTool("netmonitor").then(panel => {
- let { NetMonitorController } = panel.panelWin
- .windowRequire("devtools/client/netmonitor/src/netmonitor-controller");
- return NetMonitorController.inspectRequest(requestId);
+ let { inspectRequest } = panel.panelWin.windowRequire(
+ "devtools/client/netmonitor/src/connector/index");
+ return inspectRequest(requestId);
});
},
/**
* Handler for page location changes.
*
* @param string uri
* New page location.