зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1662736 - [devtools] Simplify the network request payload r=ochameau
Differential Revision: https://phabricator.services.mozilla.com/D94457
This commit is contained in:
Родитель
0951f9218a
Коммит
a70ec38159
|
@ -325,12 +325,12 @@ class FirefoxConnector {
|
|||
}
|
||||
|
||||
navigate() {
|
||||
if (this.dataProvider.isPayloadQueueEmpty()) {
|
||||
if (!this.dataProvider.hasPendingRequests()) {
|
||||
this.onReloaded();
|
||||
return;
|
||||
}
|
||||
const listener = () => {
|
||||
if (this.dataProvider && !this.dataProvider.isPayloadQueueEmpty()) {
|
||||
if (this.dataProvider && this.dataProvider.hasPendingRequests()) {
|
||||
return;
|
||||
}
|
||||
if (this.owner) {
|
||||
|
|
|
@ -43,8 +43,8 @@ class FirefoxDataProvider {
|
|||
// Map of the stacktrace information keyed by the actor id's
|
||||
this.stackTraceRequestInfoByActorID = new Map();
|
||||
|
||||
// Internal properties
|
||||
this.payloadQueue = new Map();
|
||||
// For tracking unfinished requests
|
||||
this.pendingRequests = new Set();
|
||||
|
||||
// Map[key string => Promise] used by `requestData` to prevent requesting the same
|
||||
// request data twice.
|
||||
|
@ -84,32 +84,14 @@ class FirefoxDataProvider {
|
|||
* Add a new network request to application state.
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @param {object} data data payload will be added to application state
|
||||
* @param {object} resource resource payload will be added to application state
|
||||
*/
|
||||
async addRequest(id, 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: payload.blockedReason,
|
||||
});
|
||||
async addRequest(id, resource) {
|
||||
// Add to the pending requests which helps when deciding if the request is complete.
|
||||
this.pendingRequests.add(id);
|
||||
|
||||
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),
|
||||
|
||||
// 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: payload.cause.stacktrace,
|
||||
},
|
||||
true
|
||||
);
|
||||
await this.actions.addRequest(id, resource, true);
|
||||
}
|
||||
|
||||
this.emit(EVENTS.REQUEST_ADDED, id);
|
||||
|
@ -287,25 +269,10 @@ class FirefoxDataProvider {
|
|||
/**
|
||||
* Public API used by the Toolbox: Tells if there is still any pending request.
|
||||
*
|
||||
* @return {boolean} returns true if the payload queue is empty
|
||||
* @return {boolean} returns true if pending requests still exist in the queue.
|
||||
*/
|
||||
isPayloadQueueEmpty() {
|
||||
return this.payloadQueue.size === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge upcoming networkEventUpdate payload into existing one.
|
||||
*
|
||||
* @param {string} id request actor id
|
||||
* @param {object} payload request data payload
|
||||
*/
|
||||
pushRequestToQueue(id, payload) {
|
||||
let payloadFromQueue = this.payloadQueue.get(id);
|
||||
if (!payloadFromQueue) {
|
||||
payloadFromQueue = {};
|
||||
this.payloadQueue.set(id, payloadFromQueue);
|
||||
}
|
||||
Object.assign(payloadFromQueue, payload);
|
||||
hasPendingRequests() {
|
||||
return this.pendingRequests.size > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -359,22 +326,7 @@ class FirefoxDataProvider {
|
|||
* @param {object} resource The network event resource
|
||||
*/
|
||||
async onNetworkResourceAvailable(resource) {
|
||||
const {
|
||||
actor,
|
||||
cause,
|
||||
fromCache,
|
||||
fromServiceWorker,
|
||||
isXHR,
|
||||
request: { method, url },
|
||||
response: { bodySize, ...responseProps },
|
||||
startedDateTime,
|
||||
isThirdPartyTrackingResource,
|
||||
referrerPolicy,
|
||||
blockedReason,
|
||||
blockingExtension,
|
||||
resourceId,
|
||||
stacktraceResourceId,
|
||||
} = resource;
|
||||
const { actor, stacktraceResourceId } = resource;
|
||||
|
||||
// Check if a stacktrace resource exists for this network resource.
|
||||
// The stacktrace event is expected to happen before the network
|
||||
|
@ -385,8 +337,10 @@ class FirefoxDataProvider {
|
|||
lastFrame,
|
||||
targetFront,
|
||||
} = this.stackTraces.get(stacktraceResourceId);
|
||||
cause.stacktraceAvailable = stacktraceAvailable;
|
||||
cause.lastFrame = lastFrame;
|
||||
|
||||
resource.cause.stacktraceAvailable = stacktraceAvailable;
|
||||
resource.cause.lastFrame = lastFrame;
|
||||
|
||||
this.stackTraces.delete(stacktraceResourceId);
|
||||
// We retrieve preliminary information about the stacktrace from the
|
||||
// NETWORK_EVENT_STACKTRACE resource via `this.stackTraces` Map,
|
||||
|
@ -398,45 +352,7 @@ class FirefoxDataProvider {
|
|||
stacktraceResourceId,
|
||||
});
|
||||
}
|
||||
|
||||
// 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,
|
||||
fromCache,
|
||||
fromServiceWorker,
|
||||
isXHR,
|
||||
method,
|
||||
startedDateTime,
|
||||
url,
|
||||
isThirdPartyTrackingResource,
|
||||
referrerPolicy,
|
||||
blockedReason,
|
||||
blockingExtension,
|
||||
resourceId,
|
||||
mimeType: resource?.content?.mimeType,
|
||||
contentSize: bodySize,
|
||||
...responseProps,
|
||||
...available,
|
||||
});
|
||||
await this.addRequest(actor, resource);
|
||||
this.emitForTests(TEST_EVENTS.NETWORK_EVENT, resource);
|
||||
}
|
||||
|
||||
|
@ -445,66 +361,23 @@ class FirefoxDataProvider {
|
|||
*
|
||||
* @param {object} resource The updated network event resource.
|
||||
*/
|
||||
async onNetworkResourceUpdated(resource, update) {
|
||||
switch (update.updateType) {
|
||||
case "securityInfo":
|
||||
this.pushRequestToQueue(resource.actor, {
|
||||
securityState: resource.securityState,
|
||||
isRacing: resource.isRacing,
|
||||
});
|
||||
break;
|
||||
case "responseStart":
|
||||
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 (resource.response.content.mimeType?.includes("text/event-stream")) {
|
||||
await this.setEventStreamFlag(resource.actor);
|
||||
}
|
||||
|
||||
this.emitForTests(
|
||||
TEST_EVENTS.STARTED_RECEIVING_RESPONSE,
|
||||
resource.actor
|
||||
);
|
||||
break;
|
||||
case "responseContent":
|
||||
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":
|
||||
// Total time doesn't have to be always set e.g. net provider enhancer
|
||||
// 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 resource.totalTime !== "undefined") {
|
||||
this.pushRequestToQueue(resource.actor, {
|
||||
totalTime: resource.totalTime,
|
||||
});
|
||||
}
|
||||
break;
|
||||
async onNetworkResourceUpdated(resource) {
|
||||
// Identify the channel as SSE if mimeType is event-stream.
|
||||
if (resource?.mimeType?.includes("text/event-stream")) {
|
||||
await this.setEventStreamFlag(resource.actor);
|
||||
}
|
||||
|
||||
// This available field helps knowing when/if updateType property is arrived
|
||||
// and can be requested via `requestData`
|
||||
this.pushRequestToQueue(resource.actor, {
|
||||
[`${update.updateType}Available`]: true,
|
||||
});
|
||||
|
||||
await this.onPayloadDataReceived(resource);
|
||||
this.pendingRequests.delete(resource.actor);
|
||||
if (this.actionsEnabled && this.actions.updateRequest) {
|
||||
await this.actions.updateRequest(resource.actor, resource, true);
|
||||
}
|
||||
|
||||
// This event is fired only once per request, once all the properties are fetched
|
||||
// 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.emitForTests(TEST_EVENTS.NETWORK_EVENT_UPDATED, resource.actor);
|
||||
this.emit(EVENTS.PAYLOAD_READY, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -564,42 +437,6 @@ class FirefoxDataProvider {
|
|||
// TODO: Emit an event for test here
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 updated network event resource are available, we flush the merged
|
||||
* request payload from pending queue and then update the component.
|
||||
*/
|
||||
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.
|
||||
if (!payload.requestHeadersAvailable || !payload.requestCookiesAvailable) {
|
||||
return;
|
||||
}
|
||||
// For unblocked requests, we should wait for all major portions to be available.
|
||||
if (
|
||||
!payload.blockedReason &&
|
||||
(!payload.eventTimingsAvailable || !payload.responseContentAvailable)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.payloadQueue.delete(resource.actor);
|
||||
|
||||
if (this.actionsEnabled && this.actions.updateRequest) {
|
||||
await this.actions.updateRequest(resource.actor, payload, true);
|
||||
}
|
||||
|
||||
// This event is fired only once per request, once all the properties are fetched
|
||||
// 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, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public connector API to lazily request HTTP details from the backend.
|
||||
*
|
||||
|
|
|
@ -170,12 +170,7 @@ HarCollector.prototype = {
|
|||
for (const resource of resources) {
|
||||
trace.log("HarCollector.onNetworkEvent; ", resource);
|
||||
|
||||
const {
|
||||
actor,
|
||||
startedDateTime,
|
||||
request: { method, url },
|
||||
isXHR,
|
||||
} = resource;
|
||||
const { actor, startedDateTime, method, url, isXHR } = resource;
|
||||
const startTime = Date.parse(startedDateTime);
|
||||
|
||||
if (this.firstRequestStart == -1) {
|
||||
|
@ -211,7 +206,7 @@ HarCollector.prototype = {
|
|||
},
|
||||
|
||||
onResourceUpdated: function(updates) {
|
||||
for (const { resource, update } of updates) {
|
||||
for (const { resource } of updates) {
|
||||
// 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
|
||||
|
@ -221,84 +216,84 @@ HarCollector.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
trace.log(
|
||||
"HarCollector.onNetworkEventUpdate; " + update.updateType,
|
||||
resource
|
||||
);
|
||||
|
||||
const includeResponseBodies = Services.prefs.getBoolPref(
|
||||
"devtools.netmonitor.har.includeResponseBodies"
|
||||
);
|
||||
|
||||
let request;
|
||||
switch (update.updateType) {
|
||||
case "requestHeaders":
|
||||
request = this.getData(
|
||||
resource.actor,
|
||||
"getRequestHeaders",
|
||||
this.onRequestHeaders
|
||||
);
|
||||
break;
|
||||
case "requestCookies":
|
||||
request = this.getData(
|
||||
resource.actor,
|
||||
"getRequestCookies",
|
||||
this.onRequestCookies
|
||||
);
|
||||
break;
|
||||
case "requestPostData":
|
||||
request = this.getData(
|
||||
resource.actor,
|
||||
"getRequestPostData",
|
||||
this.onRequestPostData
|
||||
);
|
||||
break;
|
||||
case "responseHeaders":
|
||||
request = this.getData(
|
||||
resource.actor,
|
||||
"getResponseHeaders",
|
||||
this.onResponseHeaders
|
||||
);
|
||||
break;
|
||||
case "responseCookies":
|
||||
request = this.getData(
|
||||
resource.actor,
|
||||
"getResponseCookies",
|
||||
this.onResponseCookies
|
||||
);
|
||||
break;
|
||||
case "responseStart":
|
||||
file.httpVersion = resource.response.httpVersion;
|
||||
file.status = resource.response.status;
|
||||
file.statusText = resource.response.statusText;
|
||||
break;
|
||||
case "responseContent":
|
||||
file.contentSize = resource.contentSize;
|
||||
file.mimeType = resource.mimeType;
|
||||
file.transferredSize = resource.transferredSize;
|
||||
[
|
||||
{
|
||||
type: "eventTimings",
|
||||
method: "getEventTimings",
|
||||
callbackName: "onEventTimings",
|
||||
},
|
||||
{
|
||||
type: "requestHeaders",
|
||||
method: "getRequestHeaders",
|
||||
callbackName: "onRequestHeaders",
|
||||
},
|
||||
{
|
||||
type: "requestPostData",
|
||||
method: "getRequestPostData",
|
||||
callbackName: "onRequestPostData",
|
||||
},
|
||||
{
|
||||
type: "responseHeaders",
|
||||
method: "getResponseHeaders",
|
||||
callbackName: "onResponseHeaders",
|
||||
},
|
||||
{ type: "responseStart" },
|
||||
{
|
||||
type: "responseContent",
|
||||
method: "getResponseContent",
|
||||
callbackName: "onResponseContent",
|
||||
},
|
||||
{
|
||||
type: "requestCookies",
|
||||
method: "getRequestCookies",
|
||||
callbackName: "onRequestCookies",
|
||||
},
|
||||
{
|
||||
type: "responseCookies",
|
||||
method: "getResponseCookies",
|
||||
callbackName: "onResponseCookies",
|
||||
},
|
||||
].forEach(updateType => {
|
||||
trace.log(
|
||||
"HarCollector.onNetworkEventUpdate; " + updateType.type,
|
||||
resource
|
||||
);
|
||||
|
||||
if (includeResponseBodies) {
|
||||
let request;
|
||||
if (resource[`${updateType.type}Available`]) {
|
||||
if (updateType.type == "responseStart") {
|
||||
file.httpVersion = resource.httpVersion;
|
||||
file.status = resource.status;
|
||||
file.statusText = resource.statusText;
|
||||
} else if (updateType.type == "responseContent") {
|
||||
file.contentSize = resource.contentSize;
|
||||
file.mimeType = resource.mimeType;
|
||||
file.transferredSize = resource.transferredSize;
|
||||
if (includeResponseBodies) {
|
||||
request = this.getData(
|
||||
resource.actor,
|
||||
updateType.method,
|
||||
this[updateType.callbackName]
|
||||
);
|
||||
}
|
||||
} else {
|
||||
request = this.getData(
|
||||
resource.actor,
|
||||
"getResponseContent",
|
||||
this.onResponseContent
|
||||
updateType.method,
|
||||
this[updateType.callbackName]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "eventTimings":
|
||||
request = this.getData(
|
||||
resource.actor,
|
||||
"getEventTimings",
|
||||
this.onEventTimings
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (request) {
|
||||
this.requests.push(request);
|
||||
}
|
||||
|
||||
this.resetPageLoadTimeout();
|
||||
if (request) {
|
||||
this.requests.push(request);
|
||||
}
|
||||
this.resetPageLoadTimeout();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
"use strict";
|
||||
|
||||
const { TIMING_KEYS } = require("devtools/client/netmonitor/src/constants");
|
||||
const {
|
||||
getUrlDetails,
|
||||
} = require("devtools/client/netmonitor/src/utils/request-utils");
|
||||
|
||||
var guid = 0;
|
||||
|
||||
|
@ -47,6 +50,7 @@ HarImporter.prototype = {
|
|||
startedMs: startedMs,
|
||||
method: entry.request.method,
|
||||
url: entry.request.url,
|
||||
urlDetails: getUrlDetails(entry.request.url),
|
||||
isXHR: false,
|
||||
cause: {
|
||||
loadingDocumentUri: "",
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
"use strict";
|
||||
|
||||
const {
|
||||
getUrlDetails,
|
||||
processNetworkUpdates,
|
||||
} = require("devtools/client/netmonitor/src/utils/request-utils");
|
||||
const {
|
||||
|
@ -152,11 +151,12 @@ function requestsReducer(state = Requests(), action) {
|
|||
|
||||
function addRequest(state, action) {
|
||||
const nextState = { ...state };
|
||||
|
||||
// The target front is not used and cannot be serialized by redux
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { targetFront, ...requestData } = action.data;
|
||||
const newRequest = {
|
||||
id: action.id,
|
||||
...action.data,
|
||||
urlDetails: getUrlDetails(action.data.url),
|
||||
...requestData,
|
||||
};
|
||||
|
||||
nextState.requests = [...state.requests, newRequest];
|
||||
|
|
|
@ -585,26 +585,25 @@ async function getMessagePayload(payload, getLongString) {
|
|||
|
||||
/**
|
||||
* This helper function is used for additional processing of
|
||||
* incoming network update packets. It's used by Network and
|
||||
* Console panel reducers.
|
||||
* incoming network update packets. It makes sure the only valid
|
||||
* update properties and the values are correct.
|
||||
* It's used by Network and Console panel reducers.
|
||||
* @param {object} update
|
||||
* The new update payload
|
||||
* @param {object} request
|
||||
* The current request in the state
|
||||
*/
|
||||
function processNetworkUpdates(update) {
|
||||
const result = {};
|
||||
const newRequest = {};
|
||||
for (const [key, value] of Object.entries(update)) {
|
||||
if (UPDATE_PROPS.includes(key)) {
|
||||
result[key] = value;
|
||||
|
||||
switch (key) {
|
||||
case "totalTime":
|
||||
result.totalTime = update.totalTime;
|
||||
break;
|
||||
case "requestPostData":
|
||||
result.requestHeadersFromUploadStream = value.uploadHeaders;
|
||||
break;
|
||||
newRequest[key] = value;
|
||||
if (key == "requestPostData") {
|
||||
newRequest.requestHeadersFromUploadStream = value.uploadHeaders;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -80,16 +80,17 @@ function NetworkEventMessage({
|
|||
source,
|
||||
type,
|
||||
level,
|
||||
request,
|
||||
url,
|
||||
method,
|
||||
isXHR,
|
||||
timeStamp,
|
||||
blockedReason,
|
||||
httpVersion,
|
||||
status,
|
||||
statusText,
|
||||
totalTime,
|
||||
} = message;
|
||||
|
||||
const { response = {}, totalTime } = networkMessageUpdate;
|
||||
|
||||
const { httpVersion, status, statusText } = response;
|
||||
|
||||
const topLevelClasses = ["cm-s-mozilla"];
|
||||
if (isMessageNetworkError(message)) {
|
||||
topLevelClasses.push("error");
|
||||
|
@ -139,7 +140,7 @@ function NetworkEventMessage({
|
|||
const onToggle = (messageId, e) => {
|
||||
const shouldOpenLink = (isMacOS && e.metaKey) || (!isMacOS && e.ctrlKey);
|
||||
if (shouldOpenLink) {
|
||||
serviceContainer.openLink(request.url, e);
|
||||
serviceContainer.openLink(url, e);
|
||||
e.stopPropagation();
|
||||
} else if (open) {
|
||||
dispatch(actions.messageClose(messageId));
|
||||
|
@ -149,27 +150,24 @@ function NetworkEventMessage({
|
|||
};
|
||||
|
||||
// Message body components.
|
||||
const method = dom.span({ className: "method" }, request.method);
|
||||
const requestMethod = dom.span({ className: "method" }, method);
|
||||
const xhr = isXHR
|
||||
? dom.span({ className: "xhr" }, l10n.getStr("webConsoleXhrIndicator"))
|
||||
: null;
|
||||
const requestUrl = dom.span(
|
||||
{ className: "url", title: request.url },
|
||||
request.url
|
||||
);
|
||||
const requestUrl = dom.span({ className: "url", title: url }, url);
|
||||
const statusBody = statusInfo
|
||||
? dom.a({ className: "status" }, statusInfo)
|
||||
: null;
|
||||
|
||||
const messageBody = [xhr, method, requestUrl, statusBody];
|
||||
const messageBody = [xhr, requestMethod, requestUrl, statusBody];
|
||||
|
||||
// API consumed by Net monitor UI components. Most of the method
|
||||
// are not needed in context of the Console panel (atm) and thus
|
||||
// let's just provide empty implementation.
|
||||
// Individual methods might be implemented step by step as needed.
|
||||
const connector = {
|
||||
viewSourceInDebugger: (url, line, column) => {
|
||||
serviceContainer.onViewSourceInDebugger({ url, line, column });
|
||||
viewSourceInDebugger: (srcUrl, line, column) => {
|
||||
serviceContainer.onViewSourceInDebugger({ url: srcUrl, line, column });
|
||||
},
|
||||
getLongString: grip => {
|
||||
return serviceContainer.getLongString(grip);
|
||||
|
@ -210,6 +208,7 @@ function NetworkEventMessage({
|
|||
})
|
||||
);
|
||||
|
||||
const request = { url, method };
|
||||
return Message({
|
||||
dispatch,
|
||||
messageId: id,
|
||||
|
|
|
@ -51,9 +51,7 @@ function enableNetProvider(webConsoleUI) {
|
|||
const message = updates[action.id];
|
||||
if (message && !message.openedOnce && message.source == "network") {
|
||||
dataProvider.onNetworkResourceAvailable(message);
|
||||
message.updates.forEach(updateType => {
|
||||
dataProvider.onNetworkResourceUpdated(message, { updateType });
|
||||
});
|
||||
dataProvider.onNetworkResourceUpdated(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,9 +67,7 @@ function enableNetProvider(webConsoleUI) {
|
|||
const open = allMessages.includes(actor);
|
||||
if (open) {
|
||||
const message = getMessage(newState, actor);
|
||||
message.updates.forEach(updateType => {
|
||||
dataProvider.onNetworkResourceUpdated(message, { updateType });
|
||||
});
|
||||
dataProvider.onNetworkResourceUpdated(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1359,7 +1359,7 @@ function passSearchFilters(message, filters) {
|
|||
// Look for a match in location.
|
||||
isTextInFrame(matchStr, message.frame) ||
|
||||
// Look for a match in net events.
|
||||
isTextInNetEvent(matchStr, message.request) ||
|
||||
isTextInNetEvent(matchStr, message) ||
|
||||
// Look for a match in stack-trace.
|
||||
isTextInStackTrace(matchStr, message.stacktrace) ||
|
||||
// Look for a match in messageText.
|
||||
|
@ -1445,12 +1445,10 @@ function isTextInParameter(matchStr, parameter) {
|
|||
/**
|
||||
* Returns true if given text is included in provided net event grip.
|
||||
*/
|
||||
function isTextInNetEvent(matchStr, request) {
|
||||
if (!request) {
|
||||
function isTextInNetEvent(matchStr, { method, url } = {}) {
|
||||
if (!method && !url) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { method, url } = request;
|
||||
return matchStr(method) || matchStr(url);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ add_task(async function() {
|
|||
|
||||
// clear the browser console.
|
||||
await clearOutput(hud);
|
||||
await waitForTick();
|
||||
await safeCloseBrowserConsole();
|
||||
});
|
||||
|
||||
async function testMessages(hud) {
|
||||
|
|
|
@ -24,9 +24,9 @@ add_task(async function task() {
|
|||
const currentTab = gBrowser.selectedTab;
|
||||
const target = await TargetFactory.forTab(currentTab);
|
||||
const toolbox = gDevTools.getToolbox(target);
|
||||
const panel = toolbox.getCurrentPanel().panelWin;
|
||||
|
||||
const monitor = toolbox.getCurrentPanel();
|
||||
const netReady = monitor.panelWin.api.once("NetMonitor:PayloadReady");
|
||||
const netReady = panel.api.once("NetMonitor:PayloadReady");
|
||||
|
||||
// Fire an XHR POST request.
|
||||
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() {
|
||||
|
@ -46,19 +46,7 @@ add_task(async function task() {
|
|||
const urlNode = messageNode.querySelector(".url");
|
||||
info("Network message found.");
|
||||
|
||||
const onReady = new Promise(resolve => {
|
||||
let count = 0;
|
||||
function onPayloadReady(updateCount) {
|
||||
count += updateCount;
|
||||
// Wait for all NETWORK_REQUEST updated events
|
||||
// Otherwise we may still be having pending request
|
||||
if (count == 7) {
|
||||
hud.ui.off("network-request-payload-ready", onPayloadReady);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
hud.ui.on("network-request-payload-ready", onPayloadReady);
|
||||
});
|
||||
const onReady = hud.ui.once("network-request-payload-ready");
|
||||
|
||||
// Expand network log
|
||||
urlNode.click();
|
||||
|
@ -66,6 +54,7 @@ add_task(async function task() {
|
|||
await onReady;
|
||||
|
||||
info("network-request-payload-ready received");
|
||||
|
||||
await testNetworkMessage(messageNode);
|
||||
await waitForLazyRequests(toolbox);
|
||||
});
|
||||
|
|
|
@ -27,6 +27,9 @@ registerCleanupFunction(async () => {
|
|||
});
|
||||
|
||||
add_task(async function task() {
|
||||
// Make sure the filter to show all the requests is set
|
||||
await pushPref("devtools.netmonitor.filters", '["all"]');
|
||||
|
||||
// Test that the request appears in the console.
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
const currentTab = gBrowser.selectedTab;
|
||||
|
@ -65,11 +68,14 @@ async function testNetmonitor(toolbox) {
|
|||
);
|
||||
|
||||
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");
|
||||
await waitForDOM(
|
||||
document,
|
||||
".request-list-item:first-child .requests-list-timings-total"
|
||||
);
|
||||
|
||||
is(
|
||||
store.getState().requests.requests.length,
|
||||
|
|
|
@ -40,15 +40,7 @@ add_task(async function() {
|
|||
|
||||
let failed = false;
|
||||
for (const [key, packet] of generatedStubs) {
|
||||
// packet.updates are handle by the webconsole front, and can be updated after
|
||||
// we cleaned the packet, so the order isn't guaranteed. Let's sort the array
|
||||
// here so the test doesn't fail.
|
||||
const existingPacket = existingStubs.stubPackets.get(key);
|
||||
if (packet.updates && existingPacket.updates) {
|
||||
packet.updates.sort();
|
||||
existingPacket.updates.sort();
|
||||
}
|
||||
|
||||
const packetStr = JSON.stringify(packet, null, 2);
|
||||
const existingPacketStr = JSON.stringify(existingPacket, null, 2);
|
||||
is(packetStr, existingPacketStr, `"${key}" packet has expected value`);
|
||||
|
@ -67,7 +59,6 @@ async function generateNetworkEventStubs() {
|
|||
const tab = await addTab(TEST_URI);
|
||||
const resourceWatcher = await createResourceWatcherForTab(tab);
|
||||
const stacktraces = new Map();
|
||||
|
||||
let addNetworkStub = function() {};
|
||||
let addNetworkUpdateStub = function() {};
|
||||
|
||||
|
@ -110,7 +101,6 @@ async function generateNetworkEventStubs() {
|
|||
);
|
||||
|
||||
for (const [key, code] of getCommands()) {
|
||||
const noExpectedUpdates = 7;
|
||||
const networkEventDone = new Promise(resolve => {
|
||||
addNetworkStub = resource => {
|
||||
stubs.set(key, getCleanedPacket(key, getOrderedResource(resource)));
|
||||
|
@ -118,25 +108,17 @@ async function generateNetworkEventStubs() {
|
|||
};
|
||||
});
|
||||
const networkEventUpdateDone = new Promise(resolve => {
|
||||
let updateCount = 0;
|
||||
addNetworkUpdateStub = resource => {
|
||||
const updateKey = `${key} update`;
|
||||
// make sure all the updates have been happened
|
||||
if (updateCount >= noExpectedUpdates) {
|
||||
// make sure the network event stub contains all the updates
|
||||
stubs.set(key, getCleanedPacket(key, getOrderedResource(resource)));
|
||||
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++;
|
||||
}
|
||||
stubs.set(key, getCleanedPacket(key, getOrderedResource(resource)));
|
||||
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();
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -169,15 +151,23 @@ async function generateNetworkEventStubs() {
|
|||
function getOrderedResource(resource) {
|
||||
return {
|
||||
resourceType: resource.resourceType,
|
||||
_type: resource._type,
|
||||
timeStamp: resource.timeStamp,
|
||||
node: resource.node,
|
||||
actor: resource.actor,
|
||||
startedDateTime: resource.startedDateTime,
|
||||
request: resource.request,
|
||||
method: resource.method,
|
||||
url: resource.url,
|
||||
isXHR: resource.isXHR,
|
||||
cause: resource.cause,
|
||||
response: resource.response,
|
||||
httpVersion: resource.httpVersion,
|
||||
status: resource.status,
|
||||
statusText: resource.statusText,
|
||||
headersSize: resource.headersSize,
|
||||
remoteAddress: resource.remoteAddress,
|
||||
remotePort: resource.remotePort,
|
||||
mimeType: resource.mimeType,
|
||||
waitingTime: resource.waitingTime,
|
||||
contentSize: resource.contentSize,
|
||||
transferredSize: resource.transferredSize,
|
||||
timings: resource.timings,
|
||||
private: resource.private,
|
||||
fromCache: resource.fromCache,
|
||||
|
@ -185,10 +175,11 @@ function getOrderedResource(resource) {
|
|||
isThirdPartyTrackingResource: resource.isThirdPartyTrackingResource,
|
||||
referrerPolicy: resource.referrerPolicy,
|
||||
blockedReason: resource.blockedReason,
|
||||
blockingExtension: resource.blockingExtension,
|
||||
channelId: resource.channelId,
|
||||
updates: resource.updates,
|
||||
totalTime: resource.totalTime,
|
||||
securityState: resource.securityState,
|
||||
responseCache: resource.responseCache,
|
||||
isRacing: resource.isRacing,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1704,7 +1704,12 @@ function toggleLayout(hud) {
|
|||
async function waitForLazyRequests(toolbox) {
|
||||
const { wrapper } = toolbox.getCurrentPanel().hud.ui;
|
||||
return waitUntil(() => {
|
||||
return !wrapper.networkDataProvider.lazyRequestData.size;
|
||||
return (
|
||||
!wrapper.networkDataProvider.lazyRequestData.size &&
|
||||
// Make sure that batched request updates are all complete
|
||||
// as they trigger late lazy data requests.
|
||||
!wrapper.queuedRequestUpdates.length
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -296,29 +296,8 @@ function getCleanedPacket(key, packet) {
|
|||
res.actor = existingPacket.actor;
|
||||
}
|
||||
|
||||
if (res?.request?.headersSize && existingPacket?.request?.headersSize) {
|
||||
res.request.headersSize = existingPacket.request.headersSize;
|
||||
}
|
||||
|
||||
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?.response?.waitingTime && existingPacket?.response?.waitingTime) {
|
||||
res.response.waitingTime = existingPacket.response.waitingTime;
|
||||
}
|
||||
|
||||
if (res.updates && Array.isArray(res.updates)) {
|
||||
res.updates.sort();
|
||||
if (res.waitingTime && existingPacket.waitingTime) {
|
||||
res.waitingTime = existingPacket.waitingTime;
|
||||
}
|
||||
|
||||
if (res.helperResult) {
|
||||
|
|
|
@ -23,15 +23,11 @@ rawPackets.set(`GET request`, {
|
|||
"timeStamp": 1572867483805,
|
||||
"actor": "server0.conn0.netEvent4",
|
||||
"startedDateTime": "2019-11-04T11:06:34.542Z",
|
||||
"request": {
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"method": "GET",
|
||||
"headersSize": 385
|
||||
},
|
||||
"method": "GET",
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"isXHR": false,
|
||||
"cause": {
|
||||
"type": "img",
|
||||
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
"stacktraceAvailable": true,
|
||||
"lastFrame": {
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
|
@ -41,34 +37,20 @@ rawPackets.set(`GET request`, {
|
|||
"asyncCause": null
|
||||
}
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"waitingTime": 1,
|
||||
"bodySize": 418,
|
||||
"transferredSize": 578
|
||||
},
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"status": "404",
|
||||
"statusText": "Not Found",
|
||||
"remoteAddress": "127.0.0.1",
|
||||
"remotePort": 8888,
|
||||
"mimeType": "text/html; charset=utf-8",
|
||||
"waitingTime": 1,
|
||||
"contentSize": 418,
|
||||
"transferredSize": 578,
|
||||
"timings": {},
|
||||
"private": false,
|
||||
"isThirdPartyTrackingResource": false,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"updates": [
|
||||
"eventTimings",
|
||||
"requestCookies",
|
||||
"requestHeaders",
|
||||
"responseContent",
|
||||
"responseCookies",
|
||||
"responseHeaders",
|
||||
"responseStart",
|
||||
"securityInfo"
|
||||
],
|
||||
"blockedReason": 0,
|
||||
"totalTime": 2,
|
||||
"securityState": "insecure",
|
||||
"isRacing": false
|
||||
|
@ -79,15 +61,11 @@ rawPackets.set(`GET request update`, {
|
|||
"timeStamp": 1572867483805,
|
||||
"actor": "server0.conn0.netEvent5",
|
||||
"startedDateTime": "2020-07-07T14:41:14.572Z",
|
||||
"request": {
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"method": "GET",
|
||||
"headersSize": 385
|
||||
},
|
||||
"method": "GET",
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"isXHR": false,
|
||||
"cause": {
|
||||
"type": "img",
|
||||
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
"stacktraceAvailable": true,
|
||||
"lastFrame": {
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
|
@ -97,34 +75,20 @@ rawPackets.set(`GET request update`, {
|
|||
"asyncCause": null
|
||||
}
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"waitingTime": 1,
|
||||
"bodySize": 418,
|
||||
"transferredSize": 578
|
||||
},
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"status": "404",
|
||||
"statusText": "Not Found",
|
||||
"remoteAddress": "127.0.0.1",
|
||||
"remotePort": 8888,
|
||||
"mimeType": "text/html; charset=utf-8",
|
||||
"waitingTime": 1,
|
||||
"contentSize": 418,
|
||||
"transferredSize": 578,
|
||||
"timings": {},
|
||||
"private": false,
|
||||
"isThirdPartyTrackingResource": false,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"updates": [
|
||||
"eventTimings",
|
||||
"requestCookies",
|
||||
"requestHeaders",
|
||||
"responseContent",
|
||||
"responseCookies",
|
||||
"responseHeaders",
|
||||
"responseStart",
|
||||
"securityInfo"
|
||||
],
|
||||
"blockedReason": 0,
|
||||
"totalTime": 3,
|
||||
"securityState": "insecure",
|
||||
"isRacing": false
|
||||
|
@ -135,15 +99,11 @@ rawPackets.set(`XHR GET request`, {
|
|||
"timeStamp": 1572867483805,
|
||||
"actor": "server0.conn0.netEvent21",
|
||||
"startedDateTime": "2020-07-07T14:41:14.612Z",
|
||||
"request": {
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"method": "GET",
|
||||
"headersSize": 385
|
||||
},
|
||||
"method": "GET",
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"isXHR": true,
|
||||
"cause": {
|
||||
"type": "xhr",
|
||||
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
"stacktraceAvailable": true,
|
||||
"lastFrame": {
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
|
@ -153,34 +113,20 @@ rawPackets.set(`XHR GET request`, {
|
|||
"asyncCause": null
|
||||
}
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"waitingTime": 2,
|
||||
"bodySize": 418,
|
||||
"transferredSize": 578
|
||||
},
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"status": "404",
|
||||
"statusText": "Not Found",
|
||||
"remoteAddress": "127.0.0.1",
|
||||
"remotePort": 8888,
|
||||
"mimeType": "text/html; charset=utf-8",
|
||||
"waitingTime": 1,
|
||||
"contentSize": 418,
|
||||
"transferredSize": 578,
|
||||
"timings": {},
|
||||
"private": false,
|
||||
"isThirdPartyTrackingResource": false,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"updates": [
|
||||
"eventTimings",
|
||||
"requestCookies",
|
||||
"requestHeaders",
|
||||
"responseContent",
|
||||
"responseCookies",
|
||||
"responseHeaders",
|
||||
"responseStart",
|
||||
"securityInfo"
|
||||
],
|
||||
"blockedReason": 0,
|
||||
"totalTime": 1,
|
||||
"securityState": "insecure",
|
||||
"isRacing": false
|
||||
|
@ -190,15 +136,11 @@ rawPackets.set(`XHR GET request update`, {
|
|||
"resourceType": "network-event",
|
||||
"timeStamp": 1572867483805,
|
||||
"actor": "server0.conn0.netEvent20",
|
||||
"request": {
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"method": "GET",
|
||||
"headersSize": 385
|
||||
},
|
||||
"method": "GET",
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"isXHR": true,
|
||||
"cause": {
|
||||
"type": "xhr",
|
||||
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
"stacktraceAvailable": true,
|
||||
"lastFrame": {
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
|
@ -208,34 +150,20 @@ rawPackets.set(`XHR GET request update`, {
|
|||
"asyncCause": null
|
||||
}
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"waitingTime": 2,
|
||||
"bodySize": 418,
|
||||
"transferredSize": 578
|
||||
},
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"status": "404",
|
||||
"statusText": "Not Found",
|
||||
"remoteAddress": "127.0.0.1",
|
||||
"remotePort": 8888,
|
||||
"mimeType": "text/html; charset=utf-8",
|
||||
"waitingTime": 1,
|
||||
"contentSize": 418,
|
||||
"transferredSize": 578,
|
||||
"timings": {},
|
||||
"private": false,
|
||||
"isThirdPartyTrackingResource": false,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"updates": [
|
||||
"eventTimings",
|
||||
"requestCookies",
|
||||
"requestHeaders",
|
||||
"responseContent",
|
||||
"responseCookies",
|
||||
"responseHeaders",
|
||||
"responseStart",
|
||||
"securityInfo"
|
||||
],
|
||||
"blockedReason": 0,
|
||||
"totalTime": 1,
|
||||
"securityState": "insecure",
|
||||
"isRacing": false
|
||||
|
@ -246,15 +174,11 @@ rawPackets.set(`XHR POST request`, {
|
|||
"timeStamp": 1572867483805,
|
||||
"actor": "server0.conn0.netEvent36",
|
||||
"startedDateTime": "2019-11-04T11:06:35.007Z",
|
||||
"request": {
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"method": "POST",
|
||||
"headersSize": 385
|
||||
},
|
||||
"method": "POST",
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"isXHR": true,
|
||||
"cause": {
|
||||
"type": "xhr",
|
||||
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
"stacktraceAvailable": true,
|
||||
"lastFrame": {
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
|
@ -264,34 +188,20 @@ rawPackets.set(`XHR POST request`, {
|
|||
"asyncCause": null
|
||||
}
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"waitingTime": 2,
|
||||
"bodySize": 418,
|
||||
"transferredSize": 578
|
||||
},
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"status": "404",
|
||||
"statusText": "Not Found",
|
||||
"remoteAddress": "127.0.0.1",
|
||||
"remotePort": 8888,
|
||||
"mimeType": "text/html; charset=utf-8",
|
||||
"waitingTime": 1,
|
||||
"contentSize": 418,
|
||||
"transferredSize": 578,
|
||||
"timings": {},
|
||||
"private": false,
|
||||
"isThirdPartyTrackingResource": false,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"updates": [
|
||||
"eventTimings",
|
||||
"requestCookies",
|
||||
"requestHeaders",
|
||||
"responseContent",
|
||||
"responseCookies",
|
||||
"responseHeaders",
|
||||
"responseStart",
|
||||
"securityInfo"
|
||||
],
|
||||
"blockedReason": 0,
|
||||
"totalTime": 1,
|
||||
"securityState": "insecure",
|
||||
"isRacing": false
|
||||
|
@ -301,15 +211,11 @@ rawPackets.set(`XHR POST request update`, {
|
|||
"resourceType": "network-event",
|
||||
"timeStamp": 1572867483805,
|
||||
"actor": "server0.conn0.netEvent36",
|
||||
"request": {
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"method": "POST",
|
||||
"headersSize": 385
|
||||
},
|
||||
"method": "POST",
|
||||
"url": "http://example.com/inexistent.html",
|
||||
"isXHR": true,
|
||||
"cause": {
|
||||
"type": "xhr",
|
||||
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
"stacktraceAvailable": true,
|
||||
"lastFrame": {
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html",
|
||||
|
@ -319,34 +225,20 @@ rawPackets.set(`XHR POST request update`, {
|
|||
"asyncCause": null
|
||||
}
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"waitingTime": 2,
|
||||
"bodySize": 418,
|
||||
"transferredSize": 578
|
||||
},
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"status": "404",
|
||||
"statusText": "Not Found",
|
||||
"remoteAddress": "127.0.0.1",
|
||||
"remotePort": 8888,
|
||||
"mimeType": "text/html; charset=utf-8",
|
||||
"waitingTime": 1,
|
||||
"contentSize": 418,
|
||||
"transferredSize": 578,
|
||||
"timings": {},
|
||||
"private": false,
|
||||
"isThirdPartyTrackingResource": false,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"updates": [
|
||||
"eventTimings",
|
||||
"requestCookies",
|
||||
"requestHeaders",
|
||||
"responseContent",
|
||||
"responseCookies",
|
||||
"responseHeaders",
|
||||
"responseStart",
|
||||
"securityInfo"
|
||||
],
|
||||
"blockedReason": 0,
|
||||
"totalTime": 2,
|
||||
"securityState": "insecure",
|
||||
"isRacing": false
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
|
||||
const Services = require("Services");
|
||||
const l10n = require("devtools/client/webconsole/utils/l10n");
|
||||
const {
|
||||
getUrlDetails,
|
||||
} = require("devtools/client/netmonitor/src/utils/request-utils");
|
||||
const {
|
||||
ResourceWatcher,
|
||||
} = require("devtools/shared/resources/resource-watcher");
|
||||
|
@ -362,24 +359,7 @@ function transformCSSMessageResource(cssMessageResource) {
|
|||
}
|
||||
|
||||
function transformNetworkEventResource(networkEventResource) {
|
||||
return new NetworkEventMessage({
|
||||
targetFront: networkEventResource.targetFront,
|
||||
actor: networkEventResource.actor,
|
||||
isXHR: networkEventResource.isXHR,
|
||||
request: networkEventResource.request,
|
||||
response: networkEventResource.response,
|
||||
timeStamp: networkEventResource.timeStamp,
|
||||
totalTime: networkEventResource.totalTime,
|
||||
url: networkEventResource.request.url,
|
||||
urlDetails: getUrlDetails(networkEventResource.request.url),
|
||||
method: networkEventResource.request.method,
|
||||
updates: networkEventResource.updates,
|
||||
cause: networkEventResource.cause,
|
||||
private: networkEventResource.private,
|
||||
securityState: networkEventResource.securityState,
|
||||
chromeContext: networkEventResource.chromeContext,
|
||||
blockedReason: networkEventResource.blockedReason,
|
||||
});
|
||||
return new NetworkEventMessage(networkEventResource);
|
||||
}
|
||||
|
||||
function transformEvaluationResultPacket(packet) {
|
||||
|
@ -790,8 +770,8 @@ function getNaturalOrder(messageA, messageB) {
|
|||
function isMessageNetworkError(message) {
|
||||
return (
|
||||
message.source === MESSAGE_SOURCE.NETWORK &&
|
||||
message?.response?.status &&
|
||||
message.response.status.toString().match(/^[4,5]\d\d$/)
|
||||
message?.status &&
|
||||
message?.status.toString().match(/^[4,5]\d\d$/)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -423,32 +423,13 @@ class WebConsoleUI {
|
|||
}
|
||||
|
||||
_onResourceUpdated(updates) {
|
||||
const messages = [];
|
||||
for (const { resource } of updates) {
|
||||
if (
|
||||
resource.resourceType == this.hud.resourceWatcher.TYPES.NETWORK_EVENT
|
||||
) {
|
||||
// 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 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 (resource.updates.includes("responseCache")) {
|
||||
expectedLength++;
|
||||
}
|
||||
if (resource.updates.includes("requestPostData")) {
|
||||
expectedLength++;
|
||||
}
|
||||
|
||||
if (resource.updates.length === expectedLength) {
|
||||
messages.push(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.wrapper.dispatchMessagesUpdate(messages);
|
||||
const messageUpdates = updates
|
||||
.filter(
|
||||
({ resource }) =>
|
||||
resource.resourceType == this.hud.resourceWatcher.TYPES.NETWORK_EVENT
|
||||
)
|
||||
.map(({ resource }) => resource);
|
||||
this.wrapper.dispatchMessagesUpdate(messageUpdates);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,90 +30,80 @@ module.exports = async function({
|
|||
}
|
||||
|
||||
const webConsoleFront = await targetFront.getFront("console");
|
||||
const _resources = new Map();
|
||||
const resources = new Map();
|
||||
|
||||
function onNetworkEvent(packet) {
|
||||
const actor = packet.eventActor;
|
||||
const resource = {
|
||||
|
||||
resources.set(actor.actor, {
|
||||
resourceId: actor.channelId,
|
||||
resourceType: ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
timeStamp: actor.timeStamp,
|
||||
actor: actor.actor,
|
||||
startedDateTime: actor.startedDateTime,
|
||||
request: {
|
||||
isBlocked: !!actor.blockedReason,
|
||||
types: [],
|
||||
resourceUpdates: {},
|
||||
});
|
||||
|
||||
onAvailable([
|
||||
{
|
||||
resourceId: actor.channelId,
|
||||
resourceType: ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
timeStamp: actor.timeStamp,
|
||||
actor: actor.actor,
|
||||
startedDateTime: actor.startedDateTime,
|
||||
url: actor.url,
|
||||
method: actor.method,
|
||||
isXHR: actor.isXHR,
|
||||
cause: { type: actor.cause.type },
|
||||
timings: {},
|
||||
private: actor.private,
|
||||
fromCache: actor.fromCache,
|
||||
fromServiceWorker: actor.fromServiceWorker,
|
||||
isThirdPartyTrackingResource: actor.isThirdPartyTrackingResource,
|
||||
referrerPolicy: actor.referrerPolicy,
|
||||
blockedReason: actor.blockedReason,
|
||||
blockingExtension: actor.blockingExtension,
|
||||
stacktraceResourceId:
|
||||
actor.cause.type == "websocket"
|
||||
? actor.url.replace(/^http/, "ws")
|
||||
: actor.channelId,
|
||||
},
|
||||
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,
|
||||
blockingExtension: actor.blockingExtension,
|
||||
stacktraceResourceId:
|
||||
actor.cause.type == "websocket"
|
||||
? actor.url.replace(/^http/, "ws")
|
||||
: actor.channelId,
|
||||
updates: [],
|
||||
};
|
||||
|
||||
// Lets remove the stacktrace info here as
|
||||
// it is passed from the the server by the NETWORK_EVENT_STACKTRACE
|
||||
// resource type.
|
||||
delete resource.cause.stacktraceAvailable;
|
||||
delete resource.cause.lastFrame;
|
||||
|
||||
_resources.set(actor.actor, resource);
|
||||
onAvailable([resource]);
|
||||
]);
|
||||
}
|
||||
|
||||
function onNetworkEventUpdate(packet) {
|
||||
const resource = _resources.get(packet.from);
|
||||
const resource = resources.get(packet.from);
|
||||
|
||||
if (!resource) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updateType = packet.updateType;
|
||||
const resourceUpdates = {};
|
||||
resourceUpdates.updates = [...resource.updates, updateType];
|
||||
const {
|
||||
types,
|
||||
resourceUpdates,
|
||||
resourceId,
|
||||
resourceType,
|
||||
isBlocked,
|
||||
} = resource;
|
||||
|
||||
switch (updateType) {
|
||||
case "requestHeaders":
|
||||
resourceUpdates.request = Object.assign({}, resource.request, {
|
||||
headersSize: packet.headersSize,
|
||||
});
|
||||
break;
|
||||
switch (packet.updateType) {
|
||||
case "requestPostData":
|
||||
resourceUpdates.request = Object.assign({}, resource.request, {
|
||||
bodySize: packet.dataSize,
|
||||
});
|
||||
resourceUpdates.contentSize = packet.dataSize;
|
||||
break;
|
||||
case "responseStart":
|
||||
resourceUpdates.response = Object.assign({}, resource.response, {
|
||||
httpVersion: packet.response.httpVersion,
|
||||
status: packet.response.status,
|
||||
statusText: packet.response.statusText,
|
||||
headersSize: packet.response.headersSize,
|
||||
remoteAddress: packet.response.remoteAddress,
|
||||
remotePort: packet.response.remotePort,
|
||||
content: {
|
||||
mimeType: packet.response.mimeType,
|
||||
},
|
||||
waitingTime: packet.response.waitingTime,
|
||||
});
|
||||
resourceUpdates.httpVersion = packet.response.httpVersion;
|
||||
resourceUpdates.status = packet.response.status;
|
||||
resourceUpdates.statusText = packet.response.statusText;
|
||||
resourceUpdates.remoteAddress = packet.response.remoteAddress;
|
||||
resourceUpdates.remotePort = packet.response.remotePort;
|
||||
resourceUpdates.mimeType = packet.response.mimeType;
|
||||
resourceUpdates.waitingTime = packet.response.waitingTime;
|
||||
break;
|
||||
case "responseContent":
|
||||
resourceUpdates.response = Object.assign({}, resource.response, {
|
||||
bodySize: packet.contentSize,
|
||||
transferredSize: packet.transferredSize,
|
||||
content: { mimeType: packet.mimeType },
|
||||
});
|
||||
resourceUpdates.contentSize = packet.contentSize;
|
||||
resourceUpdates.transferredSize = packet.transferredSize;
|
||||
resourceUpdates.mimeType = packet.mimeType;
|
||||
resourceUpdates.blockingExtension = packet.blockingExtension;
|
||||
resourceUpdates.blockedReason = packet.blockedReason;
|
||||
break;
|
||||
case "eventTimings":
|
||||
resourceUpdates.totalTime = packet.totalTime;
|
||||
|
@ -123,40 +113,40 @@ module.exports = async function({
|
|||
resourceUpdates.isRacing = packet.isRacing;
|
||||
break;
|
||||
case "responseCache":
|
||||
resourceUpdates.response = Object.assign({}, resource.response, {
|
||||
responseCache: packet.responseCache,
|
||||
});
|
||||
resourceUpdates.responseCache = packet.responseCache;
|
||||
break;
|
||||
}
|
||||
|
||||
// Update local resource.
|
||||
Object.assign(resource, resourceUpdates);
|
||||
resourceUpdates[`${packet.updateType}Available`] = true;
|
||||
types.push(packet.updateType);
|
||||
|
||||
if (isBlocked) {
|
||||
// Blocked requests
|
||||
if (
|
||||
!types.includes("requestHeaders") ||
|
||||
!types.includes("requestCookies")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
} else if (
|
||||
// Un-blocked requests
|
||||
!types.includes("requestHeaders") ||
|
||||
!types.includes("requestCookies") ||
|
||||
!types.includes("eventTimings") ||
|
||||
!types.includes("responseContent")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
onUpdated([
|
||||
{
|
||||
resourceType: resource.resourceType,
|
||||
resourceId: resource.resourceId,
|
||||
resourceType,
|
||||
resourceId,
|
||||
resourceUpdates,
|
||||
updateType,
|
||||
},
|
||||
]);
|
||||
|
||||
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);
|
||||
}
|
||||
resources.delete(resource.actor);
|
||||
}
|
||||
|
||||
webConsoleFront.on("serverNetworkEvent", onNetworkEvent);
|
||||
|
|
|
@ -847,4 +847,6 @@ const ResourceTransformers = {
|
|||
.ROOT_NODE]: require("devtools/shared/resources/transformers/root-node"),
|
||||
[ResourceWatcher.TYPES
|
||||
.SESSION_STORAGE]: require("devtools/shared/resources/transformers/storage-session-storage.js"),
|
||||
[ResourceWatcher.TYPES
|
||||
.NETWORK_EVENT]: require("devtools/shared/resources/transformers/network-events"),
|
||||
};
|
||||
|
|
|
@ -35,7 +35,6 @@ support-files =
|
|||
[browser_resources_getAllResources.js]
|
||||
[browser_resources_network_event_stacktraces.js]
|
||||
[browser_resources_network_events.js]
|
||||
skip-if = os == "linux" #Bug 1655183
|
||||
[browser_resources_platform_messages.js]
|
||||
[browser_resources_root_node.js]
|
||||
[browser_resources_several_resources.js]
|
||||
|
|
|
@ -18,62 +18,35 @@ add_task(async function() {
|
|||
await testNetworkEventResourcesWithExistingResources();
|
||||
await testNetworkEventResourcesWithoutExistingResources();
|
||||
|
||||
// These tests would be enabled when the server-side work is done. See Bug 1644191
|
||||
// info("Test network events server listener");
|
||||
// await pushPref("devtools.testing.enableServerWatcherSupport", true);
|
||||
// await testNetworkEventResources();
|
||||
// await testNetworkEventResourcesWithIgnoreExistingResources();
|
||||
// await testNetworkEventResourcesWithExistingResources();
|
||||
// await testNetworkEventResourcesWithoutExistingResources();
|
||||
});
|
||||
|
||||
const UPDATES = [
|
||||
"requestHeaders",
|
||||
"requestCookies",
|
||||
"responseStart",
|
||||
"securityInfo",
|
||||
"responseHeaders",
|
||||
"responseCookies",
|
||||
"eventTimings",
|
||||
"responseContent",
|
||||
];
|
||||
|
||||
async function testNetworkEventResourcesWithExistingResources() {
|
||||
info(`Tests for network event resources with the existing resources`);
|
||||
await testNetworkEventResources({
|
||||
ignoreExistingResources: false,
|
||||
// 1 available event fired, for the existing resource in the cache.
|
||||
// 1 available event fired, when live request is created.
|
||||
expectedOnAvailableCounts: 2,
|
||||
// 8 update events fired, when live request is updated.
|
||||
expectedOnUpdatedCounts: 8,
|
||||
totalExpectedOnAvailableCounts: 2,
|
||||
// 1 update events fired, when live request is updated.
|
||||
totalExpectedOnUpdatedCounts: 1,
|
||||
expectedResourcesOnAvailable: {
|
||||
[`${EXAMPLE_DOMAIN}existing_post.html`]: {
|
||||
[`${EXAMPLE_DOMAIN}cached_post.html`]: {
|
||||
resourceType: ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
request: {
|
||||
url: `${EXAMPLE_DOMAIN}existing_post.html`,
|
||||
method: "POST",
|
||||
},
|
||||
// gets reset based on the type of request
|
||||
updates: [],
|
||||
method: "POST",
|
||||
},
|
||||
[`${EXAMPLE_DOMAIN}live_get.html`]: {
|
||||
resourceType: ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
request: {
|
||||
url: `${EXAMPLE_DOMAIN}live_get.html`,
|
||||
method: "GET",
|
||||
},
|
||||
// Throttling makes us receive the available event
|
||||
// after processing all the updates events
|
||||
updates: UPDATES,
|
||||
method: "GET",
|
||||
},
|
||||
},
|
||||
expectedResourcesOnUpdated: {
|
||||
[`${EXAMPLE_DOMAIN}live_get.html`]: {
|
||||
resourceType: ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
request: {
|
||||
url: `${EXAMPLE_DOMAIN}live_get.html`,
|
||||
method: "GET",
|
||||
},
|
||||
updates: UPDATES,
|
||||
method: "GET",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -84,29 +57,19 @@ async function testNetworkEventResourcesWithoutExistingResources() {
|
|||
await testNetworkEventResources({
|
||||
ignoreExistingResources: true,
|
||||
// 1 available event fired, when live request is created.
|
||||
expectedOnAvailableCounts: 1,
|
||||
// 8 update events fired, when live request is updated.
|
||||
expectedOnUpdatedCounts: 8,
|
||||
totalExpectedOnAvailableCounts: 1,
|
||||
// 1 update events fired, when live request is updated.
|
||||
totalExpectedOnUpdatedCounts: 1,
|
||||
expectedResourcesOnAvailable: {
|
||||
[`${EXAMPLE_DOMAIN}live_get.html`]: {
|
||||
resourceType: ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
request: {
|
||||
url: `${EXAMPLE_DOMAIN}live_get.html`,
|
||||
method: "GET",
|
||||
},
|
||||
// Throttling makes us receive the available event
|
||||
// after processing all the updates events
|
||||
updates: UPDATES,
|
||||
method: "GET",
|
||||
},
|
||||
},
|
||||
expectedResourcesOnUpdated: {
|
||||
[`${EXAMPLE_DOMAIN}live_get.html`]: {
|
||||
resourceType: ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
request: {
|
||||
url: `${EXAMPLE_DOMAIN}live_get.html`,
|
||||
method: "GET",
|
||||
},
|
||||
updates: UPDATES,
|
||||
method: "GET",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -118,54 +81,34 @@ async function testNetworkEventResources(options) {
|
|||
tab
|
||||
);
|
||||
|
||||
const actualResourcesOnAvailable = {};
|
||||
const actualResourcesOnUpdated = {};
|
||||
|
||||
info(
|
||||
`Trigger some network requests *before* calling ResourceWatcher.watchResources
|
||||
in order to assert the behavior of already existing network events.`
|
||||
);
|
||||
|
||||
let onResourceAvailable = () => {};
|
||||
let onResourceUpdated = () => {};
|
||||
const waitOnAllExpectedUpdatesForExistingRequests = new Promise(resolve => {
|
||||
const existingRequestUrl = `${EXAMPLE_DOMAIN}existing_post.html`;
|
||||
|
||||
// Lets make sure there is already a network event resource in the cache.
|
||||
const waitOnRequestForResourceWatcherCache = new Promise(resolve => {
|
||||
onResourceAvailable = resources => {
|
||||
for (const resource of resources) {
|
||||
// A blocked request would only have two updates so lets also resolve here
|
||||
if (
|
||||
resource.request.url == existingRequestUrl &&
|
||||
resource.blockedReason &&
|
||||
resource.updates.length == 2
|
||||
) {
|
||||
// Reset the updates expectation as the request is blocked
|
||||
if (options.expectedResourcesOnAvailable[resource.request.url]) {
|
||||
options.expectedResourcesOnAvailable[
|
||||
resource.request.url
|
||||
].updates = [...resource.updates];
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
is(
|
||||
resource.resourceType,
|
||||
ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
"Received a network event resource"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
onResourceUpdated = updates => {
|
||||
for (const { resource } of updates) {
|
||||
// Wait until all the update events have fired for the existing request.
|
||||
// Handle both blocked and unblocked requests
|
||||
if (
|
||||
resource.request.url == existingRequestUrl &&
|
||||
(resource.updates.length == 8 ||
|
||||
(resource.blockedReason && resource.updates.length == 2))
|
||||
) {
|
||||
// Makes sure the expectation always correct (for either blocked or unblocked requests)
|
||||
if (options.expectedResourcesOnAvailable[resource.request.url]) {
|
||||
options.expectedResourcesOnAvailable[
|
||||
resource.request.url
|
||||
].updates = [...resource.updates];
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
is(
|
||||
resource.resourceType,
|
||||
ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
"Received a network update event resource"
|
||||
);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -177,23 +120,29 @@ async function testNetworkEventResources(options) {
|
|||
.then(() => {
|
||||
// We can only trigger the requests once `watchResources` settles, otherwise the
|
||||
// thread might be paused.
|
||||
triggerNetworkRequests(tab.linkedBrowser, EXISTING_REQUESTS_COMMANDS);
|
||||
triggerNetworkRequests(tab.linkedBrowser, [cachedRequest]);
|
||||
});
|
||||
});
|
||||
|
||||
await waitOnAllExpectedUpdatesForExistingRequests;
|
||||
await waitOnRequestForResourceWatcherCache;
|
||||
|
||||
const actualResourcesOnAvailable = {};
|
||||
const actualResourcesOnUpdated = {};
|
||||
|
||||
let {
|
||||
expectedOnAvailableCounts,
|
||||
expectedOnUpdatedCounts,
|
||||
totalExpectedOnAvailableCounts,
|
||||
totalExpectedOnUpdatedCounts,
|
||||
expectedResourcesOnAvailable,
|
||||
expectedResourcesOnUpdated,
|
||||
|
||||
ignoreExistingResources,
|
||||
} = options;
|
||||
|
||||
const waitForAllOnAvailableEvents = waitUntil(
|
||||
() => expectedOnAvailableCounts == 0
|
||||
const waitForAllExpectedOnAvailableEvents = waitUntil(
|
||||
() => totalExpectedOnAvailableCounts == 0
|
||||
);
|
||||
const waitForAllOnUpdatedEvents = waitUntil(
|
||||
() => expectedOnUpdatedCounts == 0
|
||||
const waitForAllExpectedOnUpdatedEvents = waitUntil(
|
||||
() => totalExpectedOnUpdatedCounts == 0
|
||||
);
|
||||
|
||||
const onAvailable = resources => {
|
||||
|
@ -203,13 +152,12 @@ async function testNetworkEventResources(options) {
|
|||
ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
"Received a network event resource"
|
||||
);
|
||||
actualResourcesOnAvailable[resource.request.url] = {
|
||||
actualResourcesOnAvailable[resource.url] = {
|
||||
resourceId: resource.resourceId,
|
||||
resourceType: resource.resourceType,
|
||||
request: resource.request,
|
||||
updates: [...resource.updates],
|
||||
method: resource.method,
|
||||
};
|
||||
expectedOnAvailableCounts--;
|
||||
totalExpectedOnAvailableCounts--;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -220,13 +168,12 @@ async function testNetworkEventResources(options) {
|
|||
ResourceWatcher.TYPES.NETWORK_EVENT,
|
||||
"Received a network update event resource"
|
||||
);
|
||||
actualResourcesOnUpdated[resource.request.url] = {
|
||||
actualResourcesOnUpdated[resource.url] = {
|
||||
resourceId: resource.resourceId,
|
||||
resourceType: resource.resourceType,
|
||||
request: resource.request,
|
||||
updates: [...resource.updates],
|
||||
method: resource.method,
|
||||
};
|
||||
expectedOnUpdatedCounts--;
|
||||
totalExpectedOnUpdatedCounts--;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -240,14 +187,17 @@ async function testNetworkEventResources(options) {
|
|||
`Trigger the rest of the requests *after* calling ResourceWatcher.watchResources
|
||||
in order to assert the behavior of live network events.`
|
||||
);
|
||||
await triggerNetworkRequests(tab.linkedBrowser, LIVE_REQUESTS_COMMANDS);
|
||||
await triggerNetworkRequests(tab.linkedBrowser, [liveRequest]);
|
||||
|
||||
await Promise.all([waitForAllOnAvailableEvents, waitForAllOnUpdatedEvents]);
|
||||
await Promise.all([
|
||||
waitForAllExpectedOnAvailableEvents,
|
||||
waitForAllExpectedOnUpdatedEvents,
|
||||
]);
|
||||
|
||||
info("Check the resources on available");
|
||||
is(
|
||||
Object.keys(actualResourcesOnAvailable).length,
|
||||
Object.keys(options.expectedResourcesOnAvailable).length,
|
||||
Object.keys(expectedResourcesOnAvailable).length,
|
||||
"Got the expected number of network events fired onAvailable"
|
||||
);
|
||||
|
||||
|
@ -259,8 +209,8 @@ async function testNetworkEventResources(options) {
|
|||
);
|
||||
|
||||
// assert the resources emitted when the network event is created
|
||||
for (const key in options.expectedResourcesOnAvailable) {
|
||||
const expected = options.expectedResourcesOnAvailable[key];
|
||||
for (const key in expectedResourcesOnAvailable) {
|
||||
const expected = expectedResourcesOnAvailable[key];
|
||||
const actual = actualResourcesOnAvailable[key];
|
||||
assertResources(actual, expected);
|
||||
}
|
||||
|
@ -269,20 +219,15 @@ async function testNetworkEventResources(options) {
|
|||
|
||||
is(
|
||||
Object.keys(actualResourcesOnUpdated).length,
|
||||
Object.keys(options.expectedResourcesOnUpdated).length,
|
||||
Object.keys(expectedResourcesOnUpdated).length,
|
||||
"Got the expected number of network events fired onUpdated"
|
||||
);
|
||||
|
||||
// assert the resources emitted when the network event is updated
|
||||
for (const key in options.expectedResourcesOnUpdated) {
|
||||
const expected = options.expectedResourcesOnUpdated[key];
|
||||
for (const key in expectedResourcesOnUpdated) {
|
||||
const expected = expectedResourcesOnUpdated[key];
|
||||
const actual = actualResourcesOnUpdated[key];
|
||||
assertResources(actual, expected);
|
||||
is(
|
||||
actual.updates.length,
|
||||
expected.updates.length,
|
||||
"The number of updates is correct"
|
||||
);
|
||||
}
|
||||
|
||||
await resourceWatcher.unwatchResources(
|
||||
|
@ -312,14 +257,8 @@ function assertResources(actual, expected) {
|
|||
expected.resourceType,
|
||||
"The resource type is correct"
|
||||
);
|
||||
is(actual.request.url, expected.request.url, "The url is correct");
|
||||
is(actual.request.method, expected.request.method, "The method is correct");
|
||||
is(actual.method, expected.method, "The method is correct");
|
||||
}
|
||||
|
||||
const EXISTING_REQUESTS_COMMANDS = [
|
||||
`await fetch("/existing_post.html", { method: "POST" });`,
|
||||
];
|
||||
|
||||
const LIVE_REQUESTS_COMMANDS = [
|
||||
`await fetch("/live_get.html", { method: "GET" });`,
|
||||
];
|
||||
const cachedRequest = `await fetch("/cached_post.html", { method: "POST" });`;
|
||||
const liveRequest = `await fetch("/live_get.html", { method: "GET" });`;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
DevToolsModules(
|
||||
"console-messages.js",
|
||||
"error-messages.js",
|
||||
"network-events.js",
|
||||
"root-node.js",
|
||||
"storage-local-storage.js",
|
||||
"storage-session-storage.js",
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/* 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 {
|
||||
getUrlDetails,
|
||||
// eslint-disable-next-line mozilla/reject-some-requires
|
||||
} = require("devtools/client/netmonitor/src/utils/request-utils");
|
||||
|
||||
module.exports = function({ resource }) {
|
||||
resource.urlDetails = getUrlDetails(resource.url);
|
||||
resource.startedMs = Date.parse(resource.startedDateTime);
|
||||
return resource;
|
||||
};
|
Загрузка…
Ссылка в новой задаче