Bug 1625909 - Use the ResourceWatcher API to fetch Network Events r=ochameau,Honza,nchevobbe

This patch migrates to using the Resource Watcher API to handle Network events, it adds a legacy listeners for the network events

Differential Revision: https://phabricator.services.mozilla.com/D71543
This commit is contained in:
Hubert Boma Manilla 2020-07-12 20:38:06 +00:00
Родитель 185c6d1087
Коммит 9bcb3649ef
30 изменённых файлов: 769 добавлений и 780 удалений

Просмотреть файл

@ -135,4 +135,4 @@ async function assertResultIsTab(dbg, index) {
el && !!el.querySelector(".tab.result-item-icon"),
"Result should be a tab"
);
}
}

Просмотреть файл

@ -742,6 +742,9 @@ Toolbox.prototype = {
}
},
_onResourceAvailable() {},
_onResourceUpdated() {},
/**
* This method focuses on attaching to one particular target.
* It ensure that the target actor is fully initialized and is watching for
@ -752,10 +755,6 @@ Toolbox.prototype = {
async _attachTarget(targetFront) {
await targetFront.attach();
// Start tracking network activity on toolbox open for targets such as tabs.
const webConsoleFront = await targetFront.getFront("console");
await webConsoleFront.startListeners(["NetworkActivity"]);
// Do not attach to the thread of additional Frame targets, as they are
// already tracked by the content process targets. At least in the context
// of the Browser Toolbox.
@ -843,6 +842,19 @@ Toolbox.prototype = {
this._onTargetDestroyed
);
// Start tracking network activity on toolbox open for targets such as tabs.
// The listeners attached here do nothing. Doing this just makes sure that
// there is always at least one listener existing for network events across
// the lifetime of the various panels, so stopping the resource watcher from
// clearing out its cache of network event resources.
await this.resourceWatcher.watchResources(
[this.resourceWatcher.TYPES.NETWORK_EVENT],
{
onAvailable: this._onResourceAvailable,
onUpdated: this._onResourceUpdated,
}
);
await domReady;
this.browserRequire = BrowserLoader({
@ -3702,6 +3714,14 @@ Toolbox.prototype = {
// Reset preferences set by the toolbox
outstanding.push(this.resetPreference());
await this.resourceWatcher.unwatchResources(
[this.resourceWatcher.TYPES.NETWORK_EVENT],
{
onAvailable: this._onResourceAvailable,
onUpdated: this._onResourceUpdated,
}
);
this.targetList.unwatchTargets(
TargetList.ALL_TYPES,
this._onTargetAvailable,

Просмотреть файл

@ -32,145 +32,32 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
// Attribute name from which to retrieve the actorID out of the target actor's form
this.formAttributeName = "consoleActor";
/**
* Holds the network requests currently displayed by the Web Console. Each key
* represents the connection ID and the value is network request information.
* @private
* @type object
*/
this._networkRequests = new Map();
this.pendingEvaluationResults = new Map();
this.onEvaluationResult = this.onEvaluationResult.bind(this);
this.onNetworkEvent = this._onNetworkEvent.bind(this);
this.onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
this.on("evaluationResult", this.onEvaluationResult);
this.on("serverNetworkEvent", this.onNetworkEvent);
this.before("consoleAPICall", this.beforeConsoleAPICall);
this.before("pageError", this.beforePageError);
this._client.on("networkEventUpdate", this.onNetworkEventUpdate);
}
getNetworkRequest(actorId) {
return this._networkRequests.get(actorId);
}
getNetworkEvents() {
return this._networkRequests.values();
this._client.on("networkEventUpdate", this._onNetworkEventUpdate);
}
get actor() {
return this.actorID;
}
/**
* The "networkEvent" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onNetworkEvent(packet) {
const actor = packet.eventActor;
const networkInfo = {
type: "networkEvent",
timeStamp: actor.timeStamp,
node: null,
actor: actor.actor,
discardRequestBody: true,
discardResponseBody: true,
startedDateTime: actor.startedDateTime,
request: {
url: actor.url,
method: actor.method,
},
isXHR: actor.isXHR,
cause: actor.cause,
response: {},
timings: {},
// track the list of network event updates
updates: [],
private: actor.private,
fromCache: actor.fromCache,
fromServiceWorker: actor.fromServiceWorker,
isThirdPartyTrackingResource: actor.isThirdPartyTrackingResource,
referrerPolicy: actor.referrerPolicy,
blockedReason: actor.blockedReason,
blockingExtension: actor.blockingExtension,
channelId: actor.channelId,
};
this._networkRequests.set(actor.actor, networkInfo);
this.emit("networkEvent", networkInfo);
}
/**
* The "networkEventUpdate" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onNetworkEventUpdate(packet) {
const networkInfo = this.getNetworkRequest(packet.from);
if (!networkInfo) {
return;
}
networkInfo.updates.push(packet.updateType);
switch (packet.updateType) {
case "requestHeaders":
networkInfo.request.headersSize = packet.headersSize;
break;
case "requestPostData":
networkInfo.discardRequestBody = packet.discardRequestBody;
networkInfo.request.bodySize = packet.dataSize;
break;
case "responseStart":
networkInfo.response.httpVersion = packet.response.httpVersion;
networkInfo.response.status = packet.response.status;
networkInfo.response.statusText = packet.response.statusText;
networkInfo.response.headersSize = packet.response.headersSize;
networkInfo.response.remoteAddress = packet.response.remoteAddress;
networkInfo.response.remotePort = packet.response.remotePort;
networkInfo.discardResponseBody = packet.response.discardResponseBody;
networkInfo.response.waitingTime = packet.response.waitingTime;
networkInfo.response.content = {
mimeType: packet.response.mimeType,
};
break;
case "responseContent":
networkInfo.response.content = {
mimeType: packet.mimeType,
};
networkInfo.response.bodySize = packet.contentSize;
networkInfo.response.transferredSize = packet.transferredSize;
networkInfo.discardResponseBody = packet.discardResponseBody;
break;
case "eventTimings":
networkInfo.totalTime = packet.totalTime;
break;
case "securityInfo":
networkInfo.securityState = packet.state;
break;
case "responseCache":
networkInfo.response.responseCache = packet.responseCache;
break;
}
this.emit("networkEventUpdate", {
packet: packet,
networkInfo,
});
this.emit("serverNetworkUpdateEvent", packet);
}
/**
@ -587,13 +474,6 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
}
}
clearNetworkRequests() {
// Prevent exception if the front has already been destroyed.
if (this._networkRequests) {
this._networkRequests.clear();
}
}
/**
* Close the WebConsoleFront.
*
@ -603,18 +483,15 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
return null;
}
this._client.off("networkEventUpdate", this.onNetworkEventUpdate);
this._client.off("networkEventUpdate", this._onNetworkEventUpdate);
// This will make future calls to this function harmless because of the early return
// at the top of the function.
this._client = null;
this.off("evaluationResult", this.onEvaluationResult);
this.off("serverNetworkEvent", this.onNetworkEvent);
this._longStrings = null;
this.pendingEvaluationResults.clear();
this.pendingEvaluationResults = null;
this.clearNetworkRequests();
this._networkRequests = null;
return super.destroy();
}
}

Просмотреть файл

@ -6,7 +6,7 @@
// panel.
const TEST_URI =
"data:text/html;charset=UTF-8," + "<p>Switch to inspector on pick</p>";
"data:text/html;charset=UTF-8,<script>console.log(`hello`)</script><p>Switch to inspector on pick</p>";
const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
const DATA = [
@ -20,7 +20,7 @@ const DATA = [
start_state: "initial_panel",
panel_name: "webconsole",
cold: "true",
message_count: "0",
message_count: "1",
width: "1300",
},
},
@ -65,7 +65,7 @@ add_task(async function() {
await startPickerAndAssertSwitchToInspector(toolbox);
info("Stoppping element picker.");
info("Stopping element picker.");
await toolbox.nodePicker.stop();
checkResults();

Просмотреть файл

@ -79,11 +79,6 @@ if (window.location.protocol === "chrome:" && url.search.length > 1) {
(async function() {
try {
const target = await targetFromURL(url);
// Start the network event listening as it is done in the toolbox code
const consoleFront = await target.getFront("console");
await consoleFront.startListeners(["NetworkActivity"]);
// Create a fake toolbox object
const toolbox = {
target,

Просмотреть файл

@ -32,7 +32,6 @@ class FirefoxConnector {
this.disconnect = this.disconnect.bind(this);
this.willNavigate = this.willNavigate.bind(this);
this.navigate = this.navigate.bind(this);
this.displayCachedEvents = this.displayCachedEvents.bind(this);
this.sendHTTPRequest = this.sendHTTPRequest.bind(this);
this.setPreferences = this.setPreferences.bind(this);
this.triggerActivity = this.triggerActivity.bind(this);
@ -44,9 +43,9 @@ class FirefoxConnector {
// Internals
this.getLongString = this.getLongString.bind(this);
this.getNetworkRequest = this.getNetworkRequest.bind(this);
this.onTargetAvailable = this.onTargetAvailable.bind(this);
this.onResourceAvailable = this.onResourceAvailable.bind(this);
this.onResourceUpdated = this.onResourceUpdated.bind(this);
}
get currentTarget() {
@ -114,7 +113,9 @@ class FirefoxConnector {
}
async resume() {
await this.addListeners();
// On resume, we shoud prevent fetching all cached network events
// and only restart recording for the new ones.
await this.addListeners(true);
}
async onTargetAvailable({ targetFront, isTargetSwitching }) {
@ -146,26 +147,35 @@ class FirefoxConnector {
// Initialize Responsive Emulation front for network throttling.
this.responsiveFront = await this.currentTarget.getFront("responsive");
// Displaying cache events is only intended for the UI panel.
if (this.actions) {
this.displayCachedEvents();
}
}
async onResourceAvailable({ resourceType, targetFront, resource }) {
if (resourceType === this.toolbox.resourceWatcher.TYPES.DOCUMENT_EVENT) {
const { TYPES } = this.toolbox.resourceWatcher;
if (resourceType === TYPES.DOCUMENT_EVENT) {
this.onDocEvent(resource);
return;
}
if (resourceType === TYPES.NETWORK_EVENT) {
this.dataProvider.onNetworkResourceAvailable(resource);
}
}
async addListeners() {
this.webConsoleFront.on("networkEvent", this.dataProvider.onNetworkEvent);
this.webConsoleFront.on(
"networkEventUpdate",
this.dataProvider.onNetworkEventUpdate
);
async onResourceUpdated({ resourceType, targetFront, resource }) {
if (resourceType === this.toolbox.resourceWatcher.TYPES.NETWORK_EVENT) {
this.dataProvider.onNetworkResourceUpdated(resource);
}
}
async addListeners(ignoreExistingResources = false) {
await this.toolbox.resourceWatcher.watchResources(
[this.toolbox.resourceWatcher.TYPES.NETWORK_EVENT],
{
onAvailable: this.onResourceAvailable,
onUpdated: this.onResourceUpdated,
ignoreExistingResources,
}
);
// Support for WebSocket monitoring is currently hidden behind this pref.
if (Services.prefs.getBoolPref("devtools.netmonitor.features.webSockets")) {
try {
@ -206,6 +216,13 @@ class FirefoxConnector {
}
removeListeners() {
this.toolbox.resourceWatcher.unwatchResources(
[this.toolbox.resourceWatcher.TYPES.NETWORK_EVENT],
{
onAvailable: this.onResourceAvailable,
onUpdated: this.onResourceUpdated,
}
);
const webSocketFront = this.currentTarget.getCachedFront("webSocket");
if (webSocketFront) {
webSocketFront.off(
@ -220,17 +237,6 @@ class FirefoxConnector {
webSocketFront.off("frameSent", this.dataProvider.onFrameSent);
}
if (this.webConsoleFront) {
this.webConsoleFront.off(
"networkEvent",
this.dataProvider.onNetworkEvent
);
this.webConsoleFront.off(
"networkEventUpdate",
this.dataProvider.onNetworkEventUpdate
);
}
const eventSourceFront = this.currentTarget.getCachedFront("eventSource");
if (eventSourceFront) {
eventSourceFront.off(
@ -300,23 +306,6 @@ class FirefoxConnector {
}
}
/**
* Display any network events already in the cache.
*/
displayCachedEvents() {
for (const networkInfo of this.webConsoleFront.getNetworkEvents()) {
// First add the request to the timeline.
this.dataProvider.onNetworkEvent(networkInfo);
// Then replay any updates already received.
for (const updateType of networkInfo.updates) {
this.dataProvider.onNetworkEventUpdate({
packet: { updateType },
networkInfo,
});
}
}
}
/**
* The "DOMContentLoaded" and "Load" events sent by the console actor.
*
@ -465,16 +454,6 @@ class FirefoxConnector {
return Promise.reject(new Error("Invalid activity type"));
}
/**
* Fetches the network information packet from actor server
*
* @param {string} id request id
* @return {object} networkInfo data packet
*/
getNetworkRequest(id) {
return this.dataProvider.getNetworkRequest(id);
}
/**
* Fetches the full text of a LongString.
*

Просмотреть файл

@ -48,8 +48,10 @@ class FirefoxDataProvider {
this.getLongString = this.getLongString.bind(this);
// Event handlers
this.onNetworkEvent = this.onNetworkEvent.bind(this);
this.onNetworkEventUpdate = this.onNetworkEventUpdate.bind(this);
this.onNetworkResourceAvailable = this.onNetworkResourceAvailable.bind(
this
);
this.onNetworkResourceUpdated = this.onNetworkResourceUpdated.bind(this);
this.onWebSocketOpened = this.onWebSocketOpened.bind(this);
this.onWebSocketClosed = this.onWebSocketClosed.bind(this);
@ -79,50 +81,26 @@ class FirefoxDataProvider {
* @param {object} data data payload will be added to application state
*/
async addRequest(id, data) {
const {
method,
url,
isXHR,
cause,
startedDateTime,
fromCache,
fromServiceWorker,
isThirdPartyTrackingResource,
referrerPolicy,
blockedReason,
blockingExtension,
channelId,
} = data;
const { startedDateTime, ...payload } = data;
// Insert blocked reason in the payload queue as well, as we'll need it later
// when deciding if the request is complete.
this.pushRequestToQueue(id, {
blockedReason,
blockedReason: payload.blockedReason,
});
if (this.actionsEnabled && this.actions.addRequest) {
await this.actions.addRequest(
id,
{
...payload,
// Convert the received date/time string to a unix timestamp.
startedMs: Date.parse(startedDateTime),
method,
url,
isXHR,
cause,
// Compatibility code to support Firefox 58 and earlier that always
// send stack-trace immediately on networkEvent message.
// FF59+ supports fetching the traces lazily via requestData.
stacktrace: cause.stacktrace,
fromCache,
fromServiceWorker,
isThirdPartyTrackingResource,
referrerPolicy,
blockedReason,
blockingExtension,
channelId,
stacktrace: payload.cause.stacktrace,
},
true
);
@ -324,16 +302,6 @@ class FirefoxDataProvider {
Object.assign(payloadFromQueue, payload);
}
/**
* Fetches the network information packet from actor server
*
* @param {string} id request id
* @return {object} networkInfo data packet
*/
getNetworkRequest(id) {
return this.webConsoleFront.getNetworkRequest(id);
}
/**
* Fetches the full text of a LongString.
*
@ -353,11 +321,11 @@ class FirefoxDataProvider {
}
/**
* The "networkEvent" message type handler.
* The handler for when the network event resource is available.
*
* @param {object} networkInfo network request information
* @param {object} resource The network event resource
*/
async onNetworkEvent(networkInfo) {
async onNetworkResourceAvailable(resource) {
const {
actor,
cause,
@ -365,13 +333,34 @@ class FirefoxDataProvider {
fromServiceWorker,
isXHR,
request: { method, url },
response: { bodySize, ...responseProps },
startedDateTime,
isThirdPartyTrackingResource,
referrerPolicy,
blockedReason,
blockingExtension,
channelId,
} = networkInfo;
} = resource;
// For resources from the resource watcher cache no updates are going to be fired
// as the resource already contains all the updated props. These need to be set so
// the UI knows the data is available on the backend.
const available = {};
[
"eventTimings",
"requestHeaders",
"requestPostData",
"responseHeaders",
"responseStart",
"responseContent",
"securityInfo",
"responseCache",
"responseCookies",
].forEach(updateType => {
if (resource.updates.includes(updateType)) {
available[`${updateType}Available`] = true;
}
});
await this.addRequest(actor, {
cause,
@ -386,56 +375,55 @@ class FirefoxDataProvider {
blockedReason,
blockingExtension,
channelId,
mimeType: resource?.content?.mimeType,
contentSize: bodySize,
...responseProps,
...available,
});
this.emitForTests(TEST_EVENTS.NETWORK_EVENT, actor);
this.emitForTests(TEST_EVENTS.NETWORK_EVENT, resource);
}
/**
* The "networkEventUpdate" message type handler.
* The handler for when the network event resource is updated.
*
* @param {object} packet the message received from the server.
* @param {object} networkInfo the network request information.
* @param {object} resource The updated network event resource.
*/
async onNetworkEventUpdate(data) {
const { packet, networkInfo } = data;
const { actor } = networkInfo;
const { updateType } = packet;
switch (updateType) {
async onNetworkResourceUpdated(resource) {
switch (resource.updateType) {
case "securityInfo":
this.pushRequestToQueue(actor, {
securityState: networkInfo.securityState,
isRacing: packet.isRacing,
this.pushRequestToQueue(resource.actor, {
securityState: resource.securityState,
isRacing: resource.isRacing,
});
break;
case "responseStart":
this.pushRequestToQueue(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,
waitingTime: networkInfo.response.waitingTime,
this.pushRequestToQueue(resource.actor, {
httpVersion: resource.response.httpVersion,
remoteAddress: resource.response.remoteAddress,
remotePort: resource.response.remotePort,
status: resource.response.status,
statusText: resource.response.statusText,
headersSize: resource.response.headersSize,
waitingTime: resource.response.waitingTime,
});
// Identify the channel as SSE if mimeType is event-stream.
if (
networkInfo.response.content.mimeType?.includes("text/event-stream")
) {
await this.setEventStreamFlag(actor);
if (resource.response.content.mimeType?.includes("text/event-stream")) {
await this.setEventStreamFlag(resource.actor);
}
this.emitForTests(TEST_EVENTS.STARTED_RECEIVING_RESPONSE, actor);
this.emitForTests(
TEST_EVENTS.STARTED_RECEIVING_RESPONSE,
resource.actor
);
break;
case "responseContent":
this.pushRequestToQueue(actor, {
contentSize: networkInfo.response.bodySize,
transferredSize: networkInfo.response.transferredSize,
mimeType: networkInfo.response.content.mimeType,
blockingExtension: packet.blockingExtension,
blockedReason: packet.blockedReason,
this.pushRequestToQueue(resource.actor, {
contentSize: resource.response.bodySize,
transferredSize: resource.response.transferredSize,
mimeType: resource.response.content.mimeType,
blockingExtension: resource.blockingExtension,
blockedReason: resource.blockedReason,
});
break;
case "eventTimings":
@ -443,19 +431,23 @@ class FirefoxDataProvider {
// in Console panel is using this method to fetch data when network log
// is expanded. So, make sure to not push undefined into the payload queue
// (it could overwrite an existing value).
if (typeof networkInfo.totalTime !== "undefined") {
this.pushRequestToQueue(actor, { totalTime: networkInfo.totalTime });
if (typeof resource.totalTime !== "undefined") {
this.pushRequestToQueue(resource.actor, {
totalTime: resource.totalTime,
});
}
break;
}
// This available field helps knowing when/if updateType property is arrived
// and can be requested via `requestData`
this.pushRequestToQueue(actor, { [`${updateType}Available`]: true });
this.pushRequestToQueue(resource.actor, {
[`${resource.updateType}Available`]: true,
});
await this.onPayloadDataReceived(actor);
await this.onPayloadDataReceived(resource);
this.emitForTests(TEST_EVENTS.NETWORK_EVENT_UPDATED, actor);
this.emitForTests(TEST_EVENTS.NETWORK_EVENT_UPDATED, resource.actor);
}
/**
@ -516,14 +508,14 @@ class FirefoxDataProvider {
}
/**
* Notify actions when messages from onNetworkEventUpdate are done, networkEventUpdate
* messages contain initial network info for each updateType and then we can invoke
* Notify actions when events from onNetworkResourceUpdated are done, updated network event
* resources contain initial network info for each updateType and then we can invoke
* requestData to fetch its corresponded data lazily.
* Once all updateTypes of networkEventUpdate message are arrived, we flush merged
* request payload from pending queue and then update component.
* Once all updateTypes of updated network event resource are available, we flush the merged
* request payload from pending queue and then update the component.
*/
async onPayloadDataReceived(actor) {
const payload = this.payloadQueue.get(actor) || {};
async onPayloadDataReceived(resource) {
const payload = this.payloadQueue.get(resource.actor) || {};
// For blocked requests, we should only expect the request portions and not
// the response portions to be available.
@ -538,17 +530,17 @@ class FirefoxDataProvider {
return;
}
this.payloadQueue.delete(actor);
this.payloadQueue.delete(resource.actor);
if (this.actionsEnabled && this.actions.updateRequest) {
await this.actions.updateRequest(actor, payload, true);
await this.actions.updateRequest(resource.actor, payload, true);
}
// This event is fired only once per request, once all the properties are fetched
// from `onNetworkEventUpdate`. There should be no more RDP requests after this.
// from `onNetworkResourceUpdated`. There should be no more RDP requests after this.
// Note that this event might be consumed by extension so, emit it in production
// release as well.
this.emit(EVENTS.PAYLOAD_READY, actor);
this.emit(EVENTS.PAYLOAD_READY, resource);
}
/**
@ -674,7 +666,7 @@ class FirefoxDataProvider {
const payload = await this.updateRequest(response.from, {
requestHeaders: response,
});
this.emitForTests(TEST_EVENTS.RECEIVED_REQUEST_HEADERS, response.from);
this.emitForTests(TEST_EVENTS.RECEIVED_REQUEST_HEADERS, response);
return payload.requestHeaders;
}
@ -687,7 +679,7 @@ class FirefoxDataProvider {
const payload = await this.updateRequest(response.from, {
responseHeaders: response,
});
this.emitForTests(TEST_EVENTS.RECEIVED_RESPONSE_HEADERS, response.from);
this.emitForTests(TEST_EVENTS.RECEIVED_RESPONSE_HEADERS, response);
return payload.responseHeaders;
}
@ -700,7 +692,7 @@ class FirefoxDataProvider {
const payload = await this.updateRequest(response.from, {
requestCookies: response,
});
this.emitForTests(TEST_EVENTS.RECEIVED_REQUEST_COOKIES, response.from);
this.emitForTests(TEST_EVENTS.RECEIVED_REQUEST_COOKIES, response);
return payload.requestCookies;
}
@ -713,7 +705,7 @@ class FirefoxDataProvider {
const payload = await this.updateRequest(response.from, {
requestPostData: response,
});
this.emitForTests(TEST_EVENTS.RECEIVED_REQUEST_POST_DATA, response.from);
this.emitForTests(TEST_EVENTS.RECEIVED_REQUEST_POST_DATA, response);
return payload.requestPostData;
}
@ -726,7 +718,7 @@ class FirefoxDataProvider {
const payload = await this.updateRequest(response.from, {
securityInfo: response.securityInfo,
});
this.emitForTests(TEST_EVENTS.RECEIVED_SECURITY_INFO, response.from);
this.emitForTests(TEST_EVENTS.RECEIVED_SECURITY_INFO, response);
return payload.securityInfo;
}
@ -739,7 +731,7 @@ class FirefoxDataProvider {
const payload = await this.updateRequest(response.from, {
responseCookies: response,
});
this.emitForTests(TEST_EVENTS.RECEIVED_RESPONSE_COOKIES, response.from);
this.emitForTests(TEST_EVENTS.RECEIVED_RESPONSE_COOKIES, response);
return payload.responseCookies;
}
@ -751,7 +743,7 @@ class FirefoxDataProvider {
const payload = await this.updateRequest(response.from, {
responseCache: response,
});
this.emitForTests(TEST_EVENTS.RECEIVED_RESPONSE_CACHE, response.from);
this.emitForTests(TEST_EVENTS.RECEIVED_RESPONSE_CACHE, response);
return payload.responseCache;
}
@ -768,7 +760,7 @@ class FirefoxDataProvider {
mimeType: response.content.mimeType,
responseContent: response,
});
this.emitForTests(TEST_EVENTS.RECEIVED_RESPONSE_CONTENT, response.from);
this.emitForTests(TEST_EVENTS.RECEIVED_RESPONSE_CONTENT, response);
return payload.responseContent;
}
@ -786,7 +778,7 @@ class FirefoxDataProvider {
// and running DAMP test doesn't set the `devtools.testing` flag.
// So, emit this event even in the production mode.
// See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1578215
this.emit(EVENTS.RECEIVED_EVENT_TIMINGS, response.from);
this.emit(EVENTS.RECEIVED_EVENT_TIMINGS, response);
return payload.eventTimings;
}
@ -799,7 +791,7 @@ class FirefoxDataProvider {
const payload = await this.updateRequest(response.from, {
stacktrace: response.stacktrace,
});
this.emitForTests(TEST_EVENTS.RECEIVED_EVENT_STACKTRACE, response.from);
this.emitForTests(TEST_EVENTS.RECEIVED_EVENT_STACKTRACE, response);
return payload.stacktrace;
}

Просмотреть файл

@ -19,7 +19,6 @@ class Connector {
this.connectChrome = this.connectChrome.bind(this);
this.connectFirefox = this.connectFirefox.bind(this);
this.getLongString = this.getLongString.bind(this);
this.getNetworkRequest = this.getNetworkRequest.bind(this);
this.getTabTarget = this.getTabTarget.bind(this);
this.sendHTTPRequest = this.sendHTTPRequest.bind(this);
this.setPreferences = this.setPreferences.bind(this);
@ -84,10 +83,6 @@ class Connector {
return this.connector.getLongString(...arguments);
}
getNetworkRequest() {
return this.connector.getNetworkRequest(...arguments);
}
getTabTarget() {
return this.connector.getTabTarget();
}

Просмотреть файл

@ -88,7 +88,7 @@ HarAutomation.prototype = {
// data from events sent from the backend.
this.collector = new HarCollector({
webConsoleFront: this.webConsoleFront,
devToolsClient: this.devToolsClient,
resourceWatcher: this.toolbox.resourceWatcher,
});
this.collector.start();

Просмотреть файл

@ -17,10 +17,10 @@ const trace = {
*/
function HarCollector(options) {
this.webConsoleFront = options.webConsoleFront;
this.devToolsClient = options.devToolsClient;
this.resourceWatcher = options.resourceWatcher;
this.onNetworkEvent = this.onNetworkEvent.bind(this);
this.onNetworkEventUpdate = this.onNetworkEventUpdate.bind(this);
this.onResourceAvailable = this.onResourceAvailable.bind(this);
this.onResourceUpdated = this.onResourceUpdated.bind(this);
this.onRequestHeaders = this.onRequestHeaders.bind(this);
this.onRequestCookies = this.onRequestCookies.bind(this);
this.onRequestPostData = this.onRequestPostData.bind(this);
@ -35,14 +35,24 @@ function HarCollector(options) {
HarCollector.prototype = {
// Connection
start: function() {
this.webConsoleFront.on("networkEvent", this.onNetworkEvent);
this.devToolsClient.on("networkEventUpdate", this.onNetworkEventUpdate);
start: async function() {
await this.resourceWatcher.watchResources(
[this.resourceWatcher.TYPES.NETWORK_EVENT],
{
onAvailable: this.onResourceAvailable,
onUpdated: this.onResourceUpdated,
}
);
},
stop: function() {
this.webConsoleFront.off("networkEvent", this.onNetworkEvent);
this.devToolsClient.off("networkEventUpdate", this.onNetworkEventUpdate);
stop: async function() {
await this.resourceWatcher.unwatchResources(
[this.resourceWatcher.TYPES.NETWORK_EVENT],
{
onAvailable: this.onResourceAvailable,
onUpdated: this.onResourceUpdated,
}
);
},
clear: function() {
@ -156,15 +166,15 @@ HarCollector.prototype = {
// Event Handlers
onNetworkEvent: function(packet) {
trace.log("HarCollector.onNetworkEvent; ", packet);
onResourceAvailable: function({ resourceType, targetFront, resource }) {
trace.log("HarCollector.onNetworkEvent; ", resource);
const {
actor,
startedDateTime,
request: { method, url },
isXHR,
} = packet;
} = resource;
const startTime = Date.parse(startedDateTime);
if (this.firstRequestStart == -1) {
@ -198,21 +208,19 @@ HarCollector.prototype = {
this.items.push(file);
},
onNetworkEventUpdate: function(packet) {
const actor = packet.from;
onResourceUpdated: function({ resourceType, targetFront, resource }) {
// Skip events from unknown actors (not in the list).
// It can happen when there are zombie requests received after
// the target is closed or multiple tabs are attached through
// one connection (one DevToolsClient object).
const file = this.getFile(packet.from);
const file = this.getFile(resource.actor);
if (!file) {
return;
}
trace.log(
"HarCollector.onNetworkEventUpdate; " + packet.updateType,
packet
"HarCollector.onNetworkEventUpdate; " + resource.updateType,
resource
);
const includeResponseBodies = Services.prefs.getBoolPref(
@ -220,62 +228,66 @@ HarCollector.prototype = {
);
let request;
switch (packet.updateType) {
switch (resource.updateType) {
case "requestHeaders":
request = this.getData(
actor,
resource.actor,
"getRequestHeaders",
this.onRequestHeaders
);
break;
case "requestCookies":
request = this.getData(
actor,
resource.actor,
"getRequestCookies",
this.onRequestCookies
);
break;
case "requestPostData":
request = this.getData(
actor,
resource.actor,
"getRequestPostData",
this.onRequestPostData
);
break;
case "responseHeaders":
request = this.getData(
actor,
resource.actor,
"getResponseHeaders",
this.onResponseHeaders
);
break;
case "responseCookies":
request = this.getData(
actor,
resource.actor,
"getResponseCookies",
this.onResponseCookies
);
break;
case "responseStart":
file.httpVersion = packet.response.httpVersion;
file.status = packet.response.status;
file.statusText = packet.response.statusText;
file.httpVersion = resource.response.httpVersion;
file.status = resource.response.status;
file.statusText = resource.response.statusText;
break;
case "responseContent":
file.contentSize = packet.contentSize;
file.mimeType = packet.mimeType;
file.transferredSize = packet.transferredSize;
file.contentSize = resource.contentSize;
file.mimeType = resource.mimeType;
file.transferredSize = resource.transferredSize;
if (includeResponseBodies) {
request = this.getData(
actor,
resource.actor,
"getResponseContent",
this.onResponseContent
);
}
break;
case "eventTimings":
request = this.getData(actor, "getEventTimings", this.onEventTimings);
request = this.getData(
resource.actor,
"getEventTimings",
this.onEventTimings
);
break;
}

Просмотреть файл

@ -82,7 +82,7 @@ async function performRequestAndWait(tab, monitor) {
* Execute simple GET request
*/
async function performPausedRequest(connector, tab, monitor) {
const wait = connector.connector.webConsoleFront.once("networkEvent");
const wait = connector.connector.webConsoleFront.once("serverNetworkEvent");
await SpecialPowers.spawn(tab.linkedBrowser, [SIMPLE_SJS], async function(
url
) {

Просмотреть файл

@ -265,8 +265,8 @@ function startNetworkEventUpdateObserver(panelWin) {
);
updatedTypes.forEach(type =>
panelWin.api.on(type, actor => {
const key = actor + "-" + type;
panelWin.api.on(type, payload => {
const key = payload.from + "-" + type;
finishedQueue[key] = finishedQueue[key] ? finishedQueue[key] - 1 : -1;
})
);
@ -279,7 +279,6 @@ async function waitForAllNetworkUpdateEvents() {
return false;
}
}
return true;
}
info("Wait for completion of all NetworkUpdateEvents packets...");
@ -331,23 +330,7 @@ function initNetMonitor(url, { requestCount, enableCache = false }) {
const markersDone = waitForTimelineMarkers(monitor);
await toggleCache(target, true);
await Promise.all([requestsDone, markersDone]);
info(
"Cache disabled when the current and all future toolboxes are open."
);
const consoleFront = await target.getFront("console");
// Remove any requests generated by the reload while toggling the cache to
// avoid interfering with the test.
isnot(
[...consoleFront.getNetworkEvents()].length,
0,
"Request to reconfigure the tab was recorded."
);
info("Clearing requests in the console client.");
await consoleFront.clearNetworkRequests();
info("Clearing requests in the UI.");
store.dispatch(Actions.clearRequests());
}
@ -397,50 +380,31 @@ function isFiltering(monitor) {
function waitForNetworkEvents(monitor, getRequests) {
return new Promise(resolve => {
const panel = monitor.panelWin;
const { getNetworkRequest } = panel.connector;
let networkEvent = 0;
let nonBlockedNetworkEvent = 0;
let payloadReady = 0;
let eventTimings = 0;
const filtering = isFiltering(monitor);
function onNetworkEvent(actor) {
const networkInfo = getNetworkRequest(actor);
if (!networkInfo) {
// Must have been related to reloading document to disable cache.
// Ignore the event.
return;
}
function onNetworkEvent(resource) {
networkEvent++;
if (!networkInfo.blockedReason) {
if (!resource.blockedReason) {
nonBlockedNetworkEvent++;
}
maybeResolve(TEST_EVENTS.NETWORK_EVENT, actor, networkInfo);
maybeResolve(TEST_EVENTS.NETWORK_EVENT, resource.actor);
}
function onPayloadReady(actor) {
const networkInfo = getNetworkRequest(actor);
if (!networkInfo) {
// Must have been related to reloading document to disable cache.
// Ignore the event.
return;
}
function onPayloadReady(resource) {
payloadReady++;
maybeResolve(EVENTS.PAYLOAD_READY, actor, networkInfo);
maybeResolve(EVENTS.PAYLOAD_READY, resource.actor);
}
function onEventTimings(actor) {
const networkInfo = getNetworkRequest(actor);
if (!networkInfo) {
// Must have been related to reloading document to disable cache.
// Ignore the event.
return;
}
function onEventTimings(response) {
eventTimings++;
maybeResolve(EVENTS.RECEIVED_EVENT_TIMINGS, actor, networkInfo);
maybeResolve(EVENTS.RECEIVED_EVENT_TIMINGS, response.from);
}
function maybeResolve(event, actor, networkInfo) {
function maybeResolve(event, actor) {
info(
"> Network event progress: " +
"NetworkEvent: " +

Просмотреть файл

@ -146,7 +146,7 @@ function messageRemove(id) {
};
}
function networkMessageUpdate(packet, idGenerator = null, response) {
function networkMessageUpdate(packet, idGenerator = null) {
if (idGenerator == null) {
idGenerator = defaultIdGenerator;
}
@ -156,7 +156,6 @@ function networkMessageUpdate(packet, idGenerator = null, response) {
return {
type: NETWORK_MESSAGE_UPDATE,
message,
response,
};
}

Просмотреть файл

@ -175,7 +175,6 @@ function NetworkEventMessage({
return serviceContainer.getLongString(grip);
},
getTabTarget: () => {},
getNetworkRequest: () => {},
sendHTTPRequest: () => {},
setPreferences: () => {},
triggerActivity: () => {},

Просмотреть файл

@ -17,7 +17,6 @@ function enableMessagesCacheClearing(webConsoleUI) {
state = reducer(state, action);
if (webConsoleUI && action.type === MESSAGES_CLEAR) {
webConsoleUI.clearNetworkRequests();
webConsoleUI.clearMessagesCache();
}
return state;

Просмотреть файл

@ -50,12 +50,9 @@ function enableNetProvider(webConsoleUI) {
const updates = getAllNetworkMessagesUpdateById(newState);
const message = updates[action.id];
if (message && !message.openedOnce && message.source == "network") {
dataProvider.onNetworkEvent(message);
dataProvider.onNetworkResourceAvailable(message);
message.updates.forEach(updateType => {
dataProvider.onNetworkEventUpdate({
packet: { updateType: updateType },
networkInfo: message,
});
dataProvider.onNetworkResourceUpdated({ ...message, updateType });
});
}
}
@ -64,18 +61,15 @@ function enableNetProvider(webConsoleUI) {
// Network event update packets are sent in batches from:
// `WebConsoleOutputWrapper.dispatchMessageUpdate` using
// NETWORK_MESSAGE_UPDATE action.
// Make sure to call `dataProvider.onNetworkEventUpdate`
// Make sure to call `dataProvider.onNetworkResourceUpdated`
// to fetch data from the backend.
if (type == NETWORK_MESSAGE_UPDATE) {
const { actor } = action.response.networkInfo;
const { actor } = action.message;
const open = getAllMessagesUiById(state).includes(actor);
if (open) {
const message = getMessage(state, actor);
message.updates.forEach(updateType => {
dataProvider.onNetworkEventUpdate({
packet: { updateType },
networkInfo: message,
});
dataProvider.onNetworkResourceUpdated({ ...message, updateType });
});
}
}

Просмотреть файл

@ -60,15 +60,18 @@ add_task(async function task() {
async function testNetmonitor(toolbox) {
const monitor = toolbox.getCurrentPanel();
const { store, windowRequire } = monitor.panelWin;
const { document, store, windowRequire } = monitor.panelWin;
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
const { getSortedRequests } = windowRequire(
"devtools/client/netmonitor/src/selectors/index"
);
store.dispatch(Actions.batchEnable(false));
const requestItem = document.querySelector(".request-list-item");
await waitUntil(() => store.getState().requests.requests.length > 0);
// Lets also wait until all the event timings data requested
// has completed and the column is rendered.
await waitForDOM(requestItem, ".requests-list-timings-total");
is(
store.getState().requests.requests.length,

Просмотреть файл

@ -4,6 +4,7 @@
"use strict";
const {
createResourceWatcherForTab,
STUBS_UPDATE_ENV,
getStubFile,
getCleanedPacket,
@ -62,31 +63,52 @@ add_task(async function() {
});
async function generateNetworkEventStubs() {
const packets = new Map();
const toolbox = await openNewTabAndToolbox(TEST_URI, "webconsole");
const { ui } = toolbox.getCurrentPanel().hud;
const stubs = new Map();
const tab = await addTab(TEST_URI);
const resourceWatcher = await createResourceWatcherForTab(tab);
let addNetworkStub = function() {};
let addNetworkUpdateStub = function() {};
const onAvailable = resource => {
addNetworkStub(resource);
};
const onUpdated = resource => {
addNetworkUpdateStub(resource);
};
await resourceWatcher.watchResources([resourceWatcher.TYPES.NETWORK_EVENT], {
onAvailable,
onUpdated,
});
for (const [key, code] of getCommands()) {
const consoleFront = await toolbox.target.getFront("console");
const onNetwork = consoleFront.once("networkEvent", packet => {
packets.set(key, getCleanedPacket(key, packet));
});
const onNetworkUpdate = ui.once("network-message-updated", res => {
const updateKey = `${key} update`;
// We cannot ensure the form of the network update packet, some properties
// might be in another order than in the original packet.
// Hand-picking only what we need should prevent this.
const packet = {
networkInfo: {
type: res.networkInfo.type,
actor: res.networkInfo.actor,
request: res.networkInfo.request,
response: res.networkInfo.response,
totalTime: res.networkInfo.totalTime,
},
const noExpectedUpdates = 7;
const networkEventDone = new Promise(resolve => {
addNetworkStub = ({ resourceType, targetFront, resource }) => {
stubs.set(key, getCleanedPacket(key, getOrderedResource(resource)));
resolve();
};
});
const networkEventUpdateDone = new Promise(resolve => {
let updateCount = 0;
addNetworkUpdateStub = ({ resourceType, targetFront, resource }) => {
const updateKey = `${key} update`;
// make sure all the updates have been happened
if (updateCount >= noExpectedUpdates) {
stubs.set(
updateKey,
// We cannot ensure the form of the resource, some properties
// might be in another order than in the original resource.
// Hand-picking only what we need should prevent this.
getCleanedPacket(updateKey, getOrderedResource(resource))
);
resolve();
} else {
updateCount++;
}
};
packets.set(updateKey, getCleanedPacket(updateKey, packet));
});
await SpecialPowers.spawn(gBrowser.selectedBrowser, [code], function(
@ -100,12 +122,42 @@ async function generateNetworkEventStubs() {
content.wrappedJSObject.triggerPacket();
script.remove();
});
await Promise.all([onNetwork, onNetworkUpdate]);
await Promise.all([networkEventDone, networkEventUpdateDone]);
}
await closeTabAndToolbox();
return packets;
resourceWatcher.unwatchResources([resourceWatcher.TYPES.NETWORK_EVENT], {
onAvailable,
onUpdated,
});
return stubs;
}
// Ensures the order of the resource properties
function getOrderedResource(resource) {
return {
resourceType: resource.resourceType,
_type: resource._type,
timeStamp: resource.timeStamp,
node: resource.node,
actor: resource.actor,
discardRequestBody: resource.discardRequestBody,
discardResponseBody: resource.discardResponseBody,
startedDateTime: resource.startedDateTime,
request: resource.request,
isXHR: resource.isXHR,
cause: resource.cause,
response: resource.response,
timings: resource.timings,
private: resource.private,
fromCache: resource.fromCache,
fromServiceWorker: resource.fromServiceWorker,
isThirdPartyTrackingResource: resource.isThirdPartyTrackingResource,
referrerPolicy: resource.referrerPolicy,
blockedReason: resource.blockedReason,
channelId: resource.channelId,
updates: resource.updates,
updateType: resource.updateType,
totalTime: resource.totalTime,
securityState: resource.securityState,
};
}
function getCommands() {

Просмотреть файл

@ -209,8 +209,8 @@ function getCleanedPacket(key, packet) {
if (res.eventActor) {
// Clean actor ids and startedDateTime on network messages.
res.eventActor.actor = existingPacket.eventActor.actor;
res.eventActor.startedDateTime = existingPacket.eventActor.startedDateTime;
res.eventActor.actor = existingPacket.actor;
res.eventActor.startedDateTime = existingPacket.startedDateTime;
}
if (res.pageError) {
@ -288,54 +288,37 @@ function getCleanedPacket(key, packet) {
res.packet = Object.assign({}, res.packet, override);
}
if (res.networkInfo) {
if (res.networkInfo.startedDateTime) {
res.networkInfo.startedDateTime =
existingPacket.networkInfo.startedDateTime;
}
if (res.startedDateTime) {
res.startedDateTime = existingPacket.startedDateTime;
}
if (res.networkInfo.totalTime) {
res.networkInfo.totalTime = existingPacket.networkInfo.totalTime;
}
if (res.totalTime && existingPacket.totalTime) {
res.totalTime = existingPacket.totalTime;
}
if (res.networkInfo.actor) {
res.networkInfo.actor = existingPacket.networkInfo.actor;
}
if (res.actor && existingPacket.actor) {
res.actor = existingPacket.actor;
}
if (res.networkInfo.request && res.networkInfo.request.headersSize) {
res.networkInfo.request.headersSize =
existingPacket.networkInfo.request.headersSize;
}
if (res?.request?.headersSize && existingPacket?.request?.headersSize) {
res.request.headersSize = existingPacket.request.headersSize;
}
if (
res.networkInfo.response &&
res.networkInfo.response.headersSize !== undefined
) {
res.networkInfo.response.headersSize =
existingPacket.networkInfo.response.headersSize;
}
if (
res.networkInfo.response &&
res.networkInfo.response.bodySize !== undefined
) {
res.networkInfo.response.bodySize =
existingPacket.networkInfo.response.bodySize;
}
if (
res.networkInfo.response &&
res.networkInfo.response.transferredSize !== undefined
) {
res.networkInfo.response.transferredSize =
existingPacket.networkInfo.response.transferredSize;
}
if (res?.response?.headersSize && existingPacket?.response?.headersSize) {
res.response.headersSize = existingPacket.response.headersSize;
}
if (res?.response?.bodySize && existingPacket?.response?.bodySize) {
res.response.bodySize = existingPacket.response.bodySize;
}
if (
res?.response?.transferredSize &&
existingPacket?.response?.transferredSize
) {
res.response.transferredSize = existingPacket.response.transferredSize;
}
if (
res.networkInfo.response &&
res.networkInfo.response.waitingTime !== undefined
) {
res.networkInfo.response.waitingTime =
existingPacket.networkInfo.response.waitingTime;
}
if (res?.response?.waitingTime && existingPacket?.response?.waitingTime) {
res.response.waitingTime = existingPacket.response.waitingTime;
}
if (res.updates && Array.isArray(res.updates)) {
@ -348,7 +331,6 @@ function getCleanedPacket(key, packet) {
existingPacket.helperResult.object
);
}
return res;
}
@ -356,11 +338,12 @@ function cleanTimeStamp(packet) {
// We want to have the same timestamp for every stub, so they won't be re-sorted when
// adding them to the store.
const uniqueTimeStamp = 1572867483805;
// lowercased timestamp
if (packet.timestamp) {
packet.timestamp = uniqueTimeStamp;
}
// camelcased timestamp
if (packet.timeStamp) {
packet.timeStamp = uniqueTimeStamp;
}
@ -392,10 +375,6 @@ function cleanTimeStamp(packet) {
if (packet?.pageError?.timeStamp) {
packet.pageError.timeStamp = uniqueTimeStamp;
}
if (packet?.networkInfo?.timeStamp) {
packet.networkInfo.timeStamp = uniqueTimeStamp;
}
}
function copyExistingActor(a, b) {
@ -462,9 +441,7 @@ const stubPackets = parsePacketsWithFronts(rawPackets);
const stubPreparedMessages = new Map();
for (const [key, packet] of Array.from(stubPackets.entries())) {
const transformedPacket = prepareMessage(${
isNetworkMessage ? "packet.networkInfo || packet" : "packet"
}, {
const transformedPacket = prepareMessage(${"packet"}, {
getNextId: () => "1",
});
const message = ${

Просмотреть файл

@ -68,8 +68,8 @@ describe("WebConsoleWrapper", () => {
getPrivatePacket("XHR POST request")
);
const postId = Symbol();
const getId = Symbol();
const postId = "pid1";
const getId = "gid1";
// Add messages in the store to make sure that update to private requests are
// removed from the queue.
@ -94,11 +94,11 @@ describe("WebConsoleWrapper", () => {
publicNetworkUpdate,
{
...getPrivatePacket("XHR GET request update"),
networkInfo: { actor: getId },
actor: getId,
},
{
...getPrivatePacket("XHR POST request update"),
networkInfo: { actor: postId },
actor: postId,
}
);

Просмотреть файл

@ -19,7 +19,8 @@ const {
const rawPackets = new Map();
rawPackets.set(`GET request`, {
"type": "networkEvent",
"resourceType": "network-event",
"_type": "NetworkEvent",
"timeStamp": 1572867483805,
"node": null,
"actor": "server0.conn0.netEvent4",
@ -29,20 +30,13 @@ rawPackets.set(`GET request`, {
"request": {
"url": "http://example.com/inexistent.html",
"method": "GET",
"headersSize": 396
"headersSize": 385
},
"isXHR": false,
"cause": {
"type": "img",
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
"lastFrame": {
"filename": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
"lineNumber": 3,
"columnNumber": 1,
"functionName": "triggerPacket",
"asyncCause": null
},
"stacktraceAvailable": true
"stacktraceAvailable": false
},
"response": {
"httpVersion": "HTTP/1.1",
@ -51,7 +45,6 @@ rawPackets.set(`GET request`, {
"headersSize": 160,
"remoteAddress": "127.0.0.1",
"remotePort": 8888,
"waitingTime": 2,
"content": {
"mimeType": "text/html; charset=utf-8"
},
@ -59,57 +52,84 @@ rawPackets.set(`GET request`, {
"transferredSize": 578
},
"timings": {},
"updates": [
"requestHeaders",
"requestCookies",
"responseStart",
"securityInfo",
"responseHeaders",
"responseCookies",
"eventTimings",
"responseContent"
],
"private": false,
"isThirdPartyTrackingResource": false,
"referrerPolicy": "no-referrer-when-downgrade",
"channelId": 265845590720515
"channelId": 265845590720515,
"updates": [
"eventTimings",
"requestCookies",
"requestHeaders",
"responseContent",
"responseCookies",
"responseHeaders",
"responseStart",
"securityInfo"
]
});
rawPackets.set(`GET request update`, {
"networkInfo": {
"type": "networkEvent",
"actor": "server0.conn0.netEvent4",
"request": {
"url": "http://example.com/inexistent.html",
"method": "GET",
"headersSize": 396
"resourceType": "network-event",
"_type": "NetworkEvent",
"timeStamp": 1572867483805,
"node": null,
"actor": "server0.conn0.netEvent5",
"discardRequestBody": true,
"discardResponseBody": false,
"startedDateTime": "2020-07-07T14:41:14.572Z",
"request": {
"url": "http://example.com/inexistent.html",
"method": "GET",
"headersSize": 385
},
"isXHR": false,
"cause": {
"type": "img",
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
"stacktraceAvailable": false
},
"response": {
"httpVersion": "HTTP/1.1",
"status": "404",
"statusText": "Not Found",
"headersSize": 160,
"remoteAddress": "127.0.0.1",
"remotePort": 8888,
"content": {
"mimeType": "text/html; charset=utf-8"
},
"response": {
"httpVersion": "HTTP/1.1",
"status": "404",
"statusText": "Not Found",
"headersSize": 160,
"remoteAddress": "127.0.0.1",
"remotePort": 8888,
"waitingTime": 2,
"content": {
"mimeType": "text/html; charset=utf-8"
},
"bodySize": 418,
"transferredSize": 578
},
"totalTime": 14
}
"bodySize": 418,
"transferredSize": 578
},
"timings": {},
"private": false,
"isThirdPartyTrackingResource": false,
"referrerPolicy": "no-referrer-when-downgrade",
"channelId": 202499118071811,
"updates": [
"eventTimings",
"requestCookies",
"requestHeaders",
"responseContent",
"responseCookies",
"responseHeaders",
"responseStart",
"securityInfo"
],
"updateType": "responseContent",
"totalTime": 3,
"securityState": "insecure"
});
rawPackets.set(`XHR GET request`, {
"type": "networkEvent",
"resourceType": "network-event",
"_type": "NetworkEvent",
"timeStamp": 1572867483805,
"node": null,
"actor": "server0.conn0.netEvent20",
"actor": "server0.conn0.netEvent21",
"discardRequestBody": true,
"discardResponseBody": true,
"startedDateTime": "2019-11-04T11:06:34.909Z",
"startedDateTime": "2020-07-07T14:41:14.612Z",
"request": {
"url": "http://example.com/inexistent.html",
"method": "GET",
@ -135,7 +155,6 @@ rawPackets.set(`XHR GET request`, {
"headersSize": 160,
"remoteAddress": "127.0.0.1",
"remotePort": 8888,
"waitingTime": 1,
"content": {
"mimeType": "text/html; charset=utf-8"
},
@ -143,61 +162,34 @@ rawPackets.set(`XHR GET request`, {
"transferredSize": 578
},
"timings": {},
"updates": [
"requestHeaders",
"requestCookies",
"responseStart",
"securityInfo",
"responseHeaders",
"responseCookies",
"eventTimings",
"responseContent"
],
"private": false,
"isThirdPartyTrackingResource": false,
"referrerPolicy": "no-referrer-when-downgrade",
"channelId": 265845590720516
"channelId": 202499118071812,
"updates": [
"eventTimings",
"requestCookies",
"requestHeaders",
"responseContent",
"responseCookies",
"responseHeaders",
"responseStart",
"securityInfo"
]
});
rawPackets.set(`XHR GET request update`, {
"networkInfo": {
"type": "networkEvent",
"actor": "server0.conn0.netEvent20",
"request": {
"url": "http://example.com/inexistent.html",
"method": "GET",
"headersSize": 385
},
"response": {
"httpVersion": "HTTP/1.1",
"status": "404",
"statusText": "Not Found",
"headersSize": 160,
"remoteAddress": "127.0.0.1",
"remotePort": 8888,
"waitingTime": 1,
"content": {
"mimeType": "text/html; charset=utf-8"
},
"bodySize": 418,
"transferredSize": 578
},
"totalTime": 0
}
});
rawPackets.set(`XHR POST request`, {
"type": "networkEvent",
"resourceType": "network-event",
"_type": "NetworkEvent",
"timeStamp": 1572867483805,
"node": null,
"actor": "server0.conn0.netEvent36",
"actor": "server0.conn0.netEvent20",
"discardRequestBody": true,
"discardResponseBody": true,
"startedDateTime": "2019-11-04T11:06:35.007Z",
"discardResponseBody": false,
"request": {
"url": "http://example.com/inexistent.html",
"method": "POST",
"headersSize": 433
"method": "GET",
"headersSize": 385
},
"isXHR": true,
"cause": {
@ -219,7 +211,6 @@ rawPackets.set(`XHR POST request`, {
"headersSize": 160,
"remoteAddress": "127.0.0.1",
"remotePort": 8888,
"waitingTime": 1,
"content": {
"mimeType": "text/html; charset=utf-8"
},
@ -227,47 +218,137 @@ rawPackets.set(`XHR POST request`, {
"transferredSize": 578
},
"timings": {},
"updates": [
"requestHeaders",
"requestCookies",
"responseStart",
"securityInfo",
"responseHeaders",
"responseCookies",
"eventTimings",
"responseContent"
],
"private": false,
"isThirdPartyTrackingResource": false,
"referrerPolicy": "no-referrer-when-downgrade",
"channelId": 265845590720517
"updates": [
"eventTimings",
"requestCookies",
"requestHeaders",
"responseContent",
"responseCookies",
"responseHeaders",
"responseStart",
"securityInfo"
],
"updateType": "responseContent",
"totalTime": 1,
"securityState": "insecure"
});
rawPackets.set(`XHR POST request`, {
"resourceType": "network-event",
"_type": "NetworkEvent",
"timeStamp": 1572867483805,
"node": null,
"actor": "server0.conn0.netEvent36",
"discardRequestBody": true,
"discardResponseBody": true,
"startedDateTime": "2019-11-04T11:06:35.007Z",
"request": {
"url": "http://example.com/inexistent.html",
"method": "POST",
"headersSize": 385
},
"isXHR": true,
"cause": {
"type": "xhr",
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
"lastFrame": {
"filename": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
"lineNumber": 4,
"columnNumber": 5,
"functionName": "triggerPacket",
"asyncCause": null
},
"stacktraceAvailable": true
},
"response": {
"httpVersion": "HTTP/1.1",
"status": "404",
"statusText": "Not Found",
"headersSize": 160,
"remoteAddress": "127.0.0.1",
"remotePort": 8888,
"content": {
"mimeType": "text/html; charset=utf-8"
},
"bodySize": 418,
"transferredSize": 578
},
"timings": {},
"private": false,
"isThirdPartyTrackingResource": false,
"referrerPolicy": "no-referrer-when-downgrade",
"channelId": 265845590720517,
"updates": [
"eventTimings",
"requestCookies",
"requestHeaders",
"responseContent",
"responseCookies",
"responseHeaders",
"responseStart",
"securityInfo"
]
});
rawPackets.set(`XHR POST request update`, {
"networkInfo": {
"type": "networkEvent",
"actor": "server0.conn0.netEvent36",
"request": {
"url": "http://example.com/inexistent.html",
"method": "POST",
"headersSize": 433
"resourceType": "network-event",
"_type": "NetworkEvent",
"timeStamp": 1572867483805,
"node": null,
"actor": "server0.conn0.netEvent36",
"discardRequestBody": true,
"discardResponseBody": false,
"request": {
"url": "http://example.com/inexistent.html",
"method": "POST",
"headersSize": 385
},
"isXHR": true,
"cause": {
"type": "xhr",
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
"lastFrame": {
"filename": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
"lineNumber": 4,
"columnNumber": 5,
"functionName": "triggerPacket",
"asyncCause": null
},
"response": {
"httpVersion": "HTTP/1.1",
"status": "404",
"statusText": "Not Found",
"headersSize": 160,
"remoteAddress": "127.0.0.1",
"remotePort": 8888,
"waitingTime": 1,
"content": {
"mimeType": "text/html; charset=utf-8"
},
"bodySize": 418,
"transferredSize": 578
"stacktraceAvailable": true
},
"response": {
"httpVersion": "HTTP/1.1",
"status": "404",
"statusText": "Not Found",
"headersSize": 160,
"remoteAddress": "127.0.0.1",
"remotePort": 8888,
"content": {
"mimeType": "text/html; charset=utf-8"
},
"totalTime": 0
}
"bodySize": 418,
"transferredSize": 578
},
"timings": {},
"private": false,
"isThirdPartyTrackingResource": false,
"referrerPolicy": "no-referrer-when-downgrade",
"updates": [
"eventTimings",
"requestCookies",
"requestHeaders",
"responseContent",
"responseCookies",
"responseHeaders",
"responseStart",
"securityInfo"
],
"updateType": "responseContent",
"totalTime": 2,
"securityState": "insecure"
});
@ -275,7 +356,7 @@ const stubPackets = parsePacketsWithFronts(rawPackets);
const stubPreparedMessages = new Map();
for (const [key, packet] of Array.from(stubPackets.entries())) {
const transformedPacket = prepareMessage(packet.networkInfo || packet, {
const transformedPacket = prepareMessage(packet, {
getNextId: () => "1",
});
const message = NetworkEventMessage(transformedPacket);

Просмотреть файл

@ -881,15 +881,9 @@ describe("Message reducer:", () => {
let updatePacket = clonePacket(stubPackets.get("GET request update"));
packet.actor = "message1";
updatePacket.networkInfo.actor = "message1";
updatePacket.actor = "message1";
dispatch(actions.messagesAdd([packet]));
dispatch(
actions.networkMessageUpdate(
updatePacket.networkInfo,
null,
updatePacket
)
);
dispatch(actions.networkMessageUpdate(updatePacket, null));
let networkUpdates = getAllNetworkMessagesUpdateById(getState());
expect(Object.keys(networkUpdates)).toEqual(["message1"]);
@ -897,15 +891,9 @@ describe("Message reducer:", () => {
packet = clonePacket(stubPackets.get("GET request"));
updatePacket = stubPackets.get("XHR GET request update");
packet.actor = "message2";
updatePacket.networkInfo.actor = "message2";
updatePacket.actor = "message2";
dispatch(actions.messagesAdd([packet]));
dispatch(
actions.networkMessageUpdate(
updatePacket.networkInfo,
null,
updatePacket
)
);
dispatch(actions.networkMessageUpdate(updatePacket, null));
networkUpdates = getAllNetworkMessagesUpdateById(getState());
expect(Object.keys(networkUpdates)).toEqual(["message1", "message2"]);
@ -915,13 +903,7 @@ describe("Message reducer:", () => {
const { dispatch, getState } = setupStore(["XHR GET request"]);
const updatePacket = stubPackets.get("XHR GET request update");
dispatch(
actions.networkMessageUpdate(
updatePacket.networkInfo,
null,
updatePacket
)
);
dispatch(actions.networkMessageUpdate(updatePacket, null));
let networkUpdates = getAllNetworkMessagesUpdateById(getState());
expect(Object.keys(networkUpdates).length > 0).toBe(true);
@ -945,37 +927,19 @@ describe("Message reducer:", () => {
stubPackets.get("XHR GET request update")
);
packet.actor = "message1";
updatePacket.networkInfo.actor = "message1";
updatePacket.actor = "message1";
dispatch(actions.messagesAdd([packet]));
dispatch(
actions.networkMessageUpdate(
updatePacket.networkInfo,
null,
updatePacket
)
);
dispatch(actions.networkMessageUpdate(updatePacket, null));
packet.actor = "message2";
updatePacket.networkInfo.actor = "message2";
updatePacket.actor = "message2";
dispatch(actions.messagesAdd([packet]));
dispatch(
actions.networkMessageUpdate(
updatePacket.networkInfo,
null,
updatePacket
)
);
dispatch(actions.networkMessageUpdate(updatePacket, null));
packet.actor = "message3";
updatePacket.networkInfo.actor = "message3";
updatePacket.actor = "message3";
dispatch(actions.messagesAdd([packet]));
dispatch(
actions.networkMessageUpdate(
updatePacket.networkInfo,
null,
updatePacket
)
);
dispatch(actions.networkMessageUpdate(updatePacket, null));
// Check that we have the expected data.
const messages = getAllMessagesById(getState());

Просмотреть файл

@ -35,11 +35,9 @@ describe("Network message reducer:", () => {
const updatePacket = clonePacket(stubPackets.get("GET request update"));
packet.actor = "message1";
updatePacket.networkInfo.actor = "message1";
updatePacket.actor = "message1";
dispatch(actions.messagesAdd([packet]));
dispatch(
actions.networkMessageUpdate(updatePacket.networkInfo, null, updatePacket)
);
dispatch(actions.networkMessageUpdate(updatePacket, null));
});
describe("networkMessagesUpdateById", () => {

Просмотреть файл

@ -115,7 +115,7 @@ function transformResource(resource) {
return transformCSSMessageResource(resource);
}
case "networkEvent": {
case ResourceWatcher.TYPES.NETWORK_EVENT: {
return transformNetworkEventResource(resource);
}

Просмотреть файл

@ -34,11 +34,8 @@ class WebConsoleConnectionProxy {
this.webConsoleUI = webConsoleUI;
this.target = target;
this.needContentProcessMessagesListener = needContentProcessMessagesListener;
this._connecter = null;
this._onNetworkEvent = this._onNetworkEvent.bind(this);
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
this._onTabNavigated = this._onTabNavigated.bind(this);
this._onTabWillNavigate = this._onTabWillNavigate.bind(this);
this._onLastPrivateContextExited = this._onLastPrivateContextExited.bind(
@ -81,9 +78,6 @@ class WebConsoleConnectionProxy {
);
await this.webConsoleUI.setSaveRequestAndResponseBodies(saveBodies);
const networkMessages = this._getNetworkMessages();
this.dispatchMessagesAdd(networkMessages);
this._addWebConsoleFrontEventListeners();
if (this.webConsoleFront && !this.webConsoleFront.hasNativeConsoleAPI) {
@ -122,19 +116,15 @@ class WebConsoleConnectionProxy {
* @returns Promise
*/
_attachConsole() {
if (!this.webConsoleFront) {
if (!this.webConsoleFront || !this.needContentProcessMessagesListener) {
return null;
}
const listeners = ["NetworkActivity"];
// Enable the forwarding of console messages to the parent process
// when we open the Browser Console or Toolbox without fission support. If Fission
// is enabled, we don't use the ContentProcessMessages listener, but attach to the
// content processes directly.
if (this.needContentProcessMessagesListener) {
listeners.push("ContentProcessMessages");
}
return this.webConsoleFront.startListeners(listeners);
return this.webConsoleFront.startListeners(["ContentProcessMessages"]);
}
/**
@ -147,8 +137,6 @@ class WebConsoleConnectionProxy {
return;
}
this.webConsoleFront.on("networkEvent", this._onNetworkEvent);
this.webConsoleFront.on("networkEventUpdate", this._onNetworkEventUpdate);
this.webConsoleFront.on(
"lastPrivateContextExited",
this._onLastPrivateContextExited
@ -165,8 +153,6 @@ class WebConsoleConnectionProxy {
* @private
*/
_removeWebConsoleFrontEventListeners() {
this.webConsoleFront.off("networkEvent", this._onNetworkEvent);
this.webConsoleFront.off("networkEventUpdate", this._onNetworkEventUpdate);
this.webConsoleFront.off(
"lastPrivateContextExited",
this._onLastPrivateContextExited
@ -177,51 +163,11 @@ class WebConsoleConnectionProxy {
);
}
/**
* Get network messages from the server.
*
* @private
* @returns An array of network messages.
*/
_getNetworkMessages() {
if (!this.webConsoleFront) {
return [];
}
return Array.from(this.webConsoleFront.getNetworkEvents());
}
_clearLogpointMessages(logpointId) {
// Some message might try to update while we are closing the toolbox.
if (!this.webConsoleUI?.wrapper) {
return;
if (this.webConsoleUI?.wrapper) {
this.webConsoleUI.wrapper.dispatchClearLogpointMessages(logpointId);
}
this.webConsoleUI.wrapper.dispatchClearLogpointMessages(logpointId);
}
/**
* The "networkEvent" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param object networkInfo
* The network request information.
*/
_onNetworkEvent(networkInfo) {
this.dispatchMessageAdd(networkInfo);
}
/**
* The "networkEventUpdate" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param object response
* The update response received from the server.
*/
_onNetworkEventUpdate(response) {
this.dispatchMessageUpdate(response.networkInfo, response);
}
/**
@ -270,39 +216,6 @@ class WebConsoleConnectionProxy {
this.webConsoleUI.handleTabWillNavigate(packet);
}
/**
* Dispatch a message add on the new frontend and emit an event for tests.
*/
dispatchMessageAdd(packet) {
// Some message might try to update while we are closing the toolbox.
if (!this.webConsoleUI?.wrapper) {
return;
}
this.webConsoleUI.wrapper.dispatchMessageAdd(packet);
}
/**
* Batched dispatch of messages.
*/
dispatchMessagesAdd(packets) {
// Some message might try to update while we are closing the toolbox.
if (!this.webConsoleUI?.wrapper) {
return;
}
this.webConsoleUI.wrapper.dispatchMessagesAdd(packets);
}
/**
* Dispatch a message event on the new frontend and emit an event for tests.
*/
dispatchMessageUpdate(networkInfo, response) {
// Some message might try to update while we are closing the toolbox.
if (!this.webConsoleUI?.wrapper) {
return;
}
this.webConsoleUI.wrapper.dispatchMessageUpdate(networkInfo, response);
}
/**
* Disconnect the Web Console from the remote server.
*

Просмотреть файл

@ -79,6 +79,7 @@ class WebConsoleUI {
this._onTargetAvailable = this._onTargetAvailable.bind(this);
this._onTargetDestroyed = this._onTargetDestroyed.bind(this);
this._onResourceAvailable = this._onResourceAvailable.bind(this);
this._onResourceUpdated = this._onResourceUpdated.bind(this);
EventEmitter.decorate(this);
}
@ -235,19 +236,13 @@ class WebConsoleUI {
if (this.wrapper) {
this.wrapper.dispatchMessagesClear();
}
this.clearNetworkRequests();
if (clearStorage) {
this.clearMessagesCache();
}
this.emitForTests("messages-cleared");
}
clearNetworkRequests() {
for (const proxy of this.getAllProxies()) {
proxy.webConsoleFront.clearNetworkRequests();
}
}
clearMessagesCache() {
for (const proxy of this.getAllProxies()) {
proxy.webConsoleFront.clearMessagesCache();
@ -342,8 +337,12 @@ class WebConsoleUI {
resourceWatcher.TYPES.CONSOLE_MESSAGE,
resourceWatcher.TYPES.ERROR_MESSAGE,
resourceWatcher.TYPES.PLATFORM_MESSAGE,
resourceWatcher.TYPES.NETWORK_EVENT,
],
{ onAvailable: this._onResourceAvailable }
{
onAvailable: this._onResourceAvailable,
onUpdated: this._onResourceUpdated,
}
);
}
@ -370,6 +369,12 @@ class WebConsoleUI {
this.wrapper.dispatchMessageAdd(resource);
}
_onResourceUpdated({ resourceType, targetFront, resource }) {
if (resourceType == this.hud.resourceWatcher.TYPES.NETWORK_EVENT) {
this.wrapper.dispatchMessageUpdate(resource);
}
}
/**
* Called any time a new target is available.
* i.e. it was already existing or has just been created.

Просмотреть файл

@ -168,9 +168,7 @@ class WebConsoleWrapper {
// since we can receive updates even if the message isn't rendered yet.
const messages = [...getAllMessagesById(store.getState()).values()];
this.queuedMessageUpdates = this.queuedMessageUpdates.filter(
({ networkInfo }) => {
const { actor } = networkInfo;
({ actor }) => {
const queuedNetworkMessage = this.queuedMessageAdds.find(
p => p.actor === actor
);
@ -210,24 +208,24 @@ class WebConsoleWrapper {
store.dispatch(actions.privateMessagesClear());
}
dispatchMessageUpdate(message, res) {
dispatchMessageUpdate(message) {
// network-message-updated will emit when all the update message arrives.
// Since we can't ensure the order of the network update, we check
// that networkInfo.updates has all we need.
// that message.updates has all we need.
// Note that 'requestPostData' is sent only for POST requests, so we need
// to count with that.
const NUMBER_OF_NETWORK_UPDATE = 8;
let expectedLength = NUMBER_OF_NETWORK_UPDATE;
if (res.networkInfo.updates.includes("responseCache")) {
if (message.updates.includes("responseCache")) {
expectedLength++;
}
if (res.networkInfo.updates.includes("requestPostData")) {
if (message.updates.includes("requestPostData")) {
expectedLength++;
}
if (res.networkInfo.updates.length === expectedLength) {
this.batchedMessageUpdates({ res, message });
if (message.updates.length === expectedLength) {
this.batchedMessageUpdates(message);
}
}
@ -257,7 +255,6 @@ class WebConsoleWrapper {
packet.timeStamp = Date.now();
this.dispatchMessageAdd(packet);
} else {
this.webConsoleUI.clearNetworkRequests();
this.dispatchMessagesClear();
store.dispatch({
type: Constants.WILL_NAVIGATE,
@ -265,8 +262,8 @@ class WebConsoleWrapper {
}
}
batchedMessageUpdates(info) {
this.queuedMessageUpdates.push(info);
batchedMessageUpdates(message) {
this.queuedMessageUpdates.push(message);
this.setTimeoutIfNeeded();
}
@ -345,11 +342,9 @@ class WebConsoleWrapper {
this.queuedMessageAdds = [];
if (this.queuedMessageUpdates.length > 0) {
for (const { message, res } of this.queuedMessageUpdates) {
await store.dispatch(
actions.networkMessageUpdate(message, null, res)
);
this.webConsoleUI.emitForTests("network-message-updated", res);
for (const message of this.queuedMessageUpdates) {
await store.dispatch(actions.networkMessageUpdate(message, null));
this.webConsoleUI.emitForTests("network-message-updated", message);
}
this.queuedMessageUpdates = [];
}

Просмотреть файл

@ -7,6 +7,7 @@ DevToolsModules(
'css-changes.js',
'css-messages.js',
'error-messages.js',
'network-events.js',
'platform-messages.js',
'root-node.js',
'stylesheet.js',

Просмотреть файл

@ -0,0 +1,142 @@
/* 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 {
ResourceWatcher,
} = require("devtools/shared/resources/resource-watcher");
module.exports = async function({
targetList,
targetFront,
isFissionEnabledOnContentToolbox,
onAvailable,
onUpdated,
}) {
// Allow the top level target unconditionnally.
// Also allow frame, but only in content toolbox, when the fission/content toolbox pref is
// set. i.e. still ignore them in the content of the browser toolbox as we inspect
// messages via the process targets
// Also ignore workers as they are not supported yet. (see bug 1592584)
const isContentToolbox = targetList.targetFront.isLocalTab;
const listenForFrames = isContentToolbox && isFissionEnabledOnContentToolbox;
const isAllowed =
targetFront.isTopLevel ||
targetFront.targetType === targetList.TYPES.PROCESS ||
(targetFront.targetType === targetList.TYPES.FRAME && listenForFrames);
if (!isAllowed) {
return;
}
const webConsoleFront = await targetFront.getFront("console");
const _resources = new Map();
function onNetworkEvent(packet) {
const actor = packet.eventActor;
const resource = {
resourceType: ResourceWatcher.TYPES.NETWORK_EVENT,
_type: "NetworkEvent",
timeStamp: actor.timeStamp,
node: null,
actor: actor.actor,
discardRequestBody: true,
discardResponseBody: true,
startedDateTime: actor.startedDateTime,
request: {
url: actor.url,
method: actor.method,
},
isXHR: actor.isXHR,
cause: actor.cause,
response: {},
timings: {},
private: actor.private,
fromCache: actor.fromCache,
fromServiceWorker: actor.fromServiceWorker,
isThirdPartyTrackingResource: actor.isThirdPartyTrackingResource,
referrerPolicy: actor.referrerPolicy,
blockedReason: actor.blockedReason,
channelId: actor.channelId,
updates: [],
};
_resources.set(actor.actor, resource);
onAvailable([resource]);
}
function onNetworkEventUpdate(packet) {
const resource = _resources.get(packet.from);
if (!resource) {
return;
}
resource.updates.push(packet.updateType);
resource.updateType = packet.updateType;
switch (packet.updateType) {
case "requestHeaders":
resource.request.headersSize = packet.headersSize;
break;
case "requestPostData":
resource.discardRequestBody = packet.discardRequestBody;
resource.request.bodySize = packet.dataSize;
break;
case "responseStart":
resource.response.httpVersion = packet.response.httpVersion;
resource.response.status = packet.response.status;
resource.response.statusText = packet.response.statusText;
resource.response.headersSize = packet.response.headersSize;
resource.response.remoteAddress = packet.response.remoteAddress;
resource.response.remotePort = packet.response.remotePort;
resource.discardResponseBody = packet.response.discardResponseBody;
resource.response.content = {
mimeType: packet.response.mimeType,
};
break;
case "responseContent":
resource.response.content = {
mimeType: packet.mimeType,
};
resource.response.bodySize = packet.contentSize;
resource.response.transferredSize = packet.transferredSize;
resource.discardResponseBody = packet.discardResponseBody;
break;
case "eventTimings":
resource.totalTime = packet.totalTime;
break;
case "securityInfo":
resource.securityState = packet.state;
break;
case "responseCache":
resource.response.responseCache = packet.responseCache;
break;
}
onUpdated(resource);
if (resource.blockedReason) {
// Blocked requests
if (
resource.updates.includes("requestHeaders") &&
resource.updates.includes("requestCookies")
) {
_resources.delete(resource.actor);
}
} else if (
resource.updates.includes("requestHeaders") &&
resource.updates.includes("requestCookies") &&
resource.updates.includes("eventTimings") &&
resource.updates.includes("responseContent")
) {
_resources.delete(resource.actor);
}
}
webConsoleFront.on("serverNetworkEvent", onNetworkEvent);
webConsoleFront.on("serverNetworkUpdateEvent", onNetworkEventUpdate);
// Start listening to network events
webConsoleFront.startListeners(["NetworkActivity"]);
};

Просмотреть файл

@ -34,6 +34,7 @@ class ResourceWatcher {
this._onResourceDestroyed = this._onResourceDestroyed.bind(this);
this._availableListeners = new EventEmitter();
this._updatedListeners = new EventEmitter();
this._destroyedListeners = new EventEmitter();
// Cache for all resources by the order that the resource was taken.
@ -72,6 +73,7 @@ class ResourceWatcher {
async watchResources(resources, options) {
const {
onAvailable,
onUpdated,
onDestroyed,
ignoreExistingResources = false,
} = options;
@ -105,7 +107,9 @@ class ResourceWatcher {
await this._startListening(resource);
}
this._availableListeners.on(resource, onAvailable);
if (onUpdated) {
this._updatedListeners.on(resource, onUpdated);
}
if (onDestroyed) {
this._destroyedListeners.on(resource, onDestroyed);
}
@ -121,9 +125,12 @@ class ResourceWatcher {
* See `watchResources` for the arguments as both methods receive the same.
*/
unwatchResources(resources, options) {
const { onAvailable, onDestroyed } = options;
const { onAvailable, onUpdated, onDestroyed } = options;
for (const resource of resources) {
if (onUpdated) {
this._updatedListeners.off(resource, onUpdated);
}
if (onDestroyed) {
this._destroyedListeners.off(resource, onDestroyed);
}
@ -295,6 +302,27 @@ class ResourceWatcher {
}
}
/**
* Method called either by:
* - the backward compatibility code (LegacyListeners)
* - target actors RDP events
* Called everytime a resource is updated in the remote target.
*
* @param {Front} targetFront
* The Target Front from which this resource comes from.
* @param {Array<json/Front>} resources
* Depending on the resource Type, it can be an Array composed of either JSON objects or Fronts,
* which describes the updated resource.
*/
_onResourceUpdated(targetFront, resource) {
const { resourceType } = resource;
this._updatedListeners.emit(resourceType, {
resourceType,
targetFront,
resource,
});
}
/**
* Called everytime a resource is destroyed in the remote target.
* See _onResourceAvailable for the argument description.
@ -384,11 +412,13 @@ class ResourceWatcher {
*/
_watchResourcesForTarget(targetFront, resourceType) {
const onAvailable = this._onResourceAvailable.bind(this, { targetFront });
const onUpdated = this._onResourceUpdated.bind(this, { targetFront });
return LegacyListeners[resourceType]({
targetList: this.targetList,
targetFront,
isFissionEnabledOnContentToolbox: gDevTools.isFissionContentToolboxEnabled(),
onAvailable,
onUpdated,
});
}
@ -456,6 +486,7 @@ ResourceWatcher.TYPES = ResourceWatcher.prototype.TYPES = {
DOCUMENT_EVENT: "document-event",
ROOT_NODE: "root-node",
STYLESHEET: "stylesheet",
NETWORK_EVENT: "network-event",
};
module.exports = { ResourceWatcher };
@ -494,6 +525,8 @@ const LegacyListeners = {
.ROOT_NODE]: require("devtools/shared/resources/legacy-listeners/root-node"),
[ResourceWatcher.TYPES
.STYLESHEET]: require("devtools/shared/resources/legacy-listeners/stylesheet"),
[ResourceWatcher.TYPES
.NETWORK_EVENT]: require("devtools/shared/resources/legacy-listeners/network-events"),
};
// Optional transformers for each type of resource.