зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 1134073) for browser_net_statistics-01.js failures
Backed out a58743e540f5 (bug 1134073) Backed out 616b2bbf8fd0 (bug 1134073) Backed out 691b0e0a6ca1 (bug 1134073) MozReview-Commit-ID: 3LwVxPXX8SZ
This commit is contained in:
Родитель
e9eb52b1c2
Коммит
b45619ad94
|
@ -39,10 +39,6 @@
|
|||
- in the network table toolbar, above the "domain" column. -->
|
||||
<!ENTITY netmonitorUI.toolbar.domain "Domain">
|
||||
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.cause): This is the label displayed
|
||||
- in the network table toolbar, above the "cause" column. -->
|
||||
<!ENTITY netmonitorUI.toolbar.cause "Cause">
|
||||
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.type): This is the label displayed
|
||||
- in the network table toolbar, above the "type" column. -->
|
||||
<!ENTITY netmonitorUI.toolbar.type "Type">
|
||||
|
|
|
@ -433,13 +433,6 @@ var NetMonitorController = {
|
|||
get supportsPerfStats() {
|
||||
return this.tabClient &&
|
||||
(this.tabClient.traits.reconfigure || !this._target.isApp);
|
||||
},
|
||||
|
||||
/**
|
||||
* Open a given source in Debugger
|
||||
*/
|
||||
viewSourceInDebugger(sourceURL, sourceLine) {
|
||||
return this._toolbox.viewSourceInDebugger(sourceURL, sourceLine);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -636,14 +629,12 @@ NetworkEventsHandler.prototype = {
|
|||
startedDateTime,
|
||||
request: { method, url },
|
||||
isXHR,
|
||||
cause,
|
||||
fromCache,
|
||||
fromServiceWorker
|
||||
} = networkInfo;
|
||||
|
||||
NetMonitorView.RequestsMenu.addRequest(
|
||||
actor, startedDateTime, method, url, isXHR, cause, fromCache,
|
||||
fromServiceWorker
|
||||
actor, startedDateTime, method, url, isXHR, fromCache, fromServiceWorker
|
||||
);
|
||||
window.emit(EVENTS.NETWORK_EVENT, actor);
|
||||
},
|
||||
|
|
|
@ -30,9 +30,7 @@ const {ViewHelpers, Heritage, WidgetMethods, setNamedTimeout} =
|
|||
* Localization convenience methods.
|
||||
*/
|
||||
const NET_STRINGS_URI = "chrome://devtools/locale/netmonitor.properties";
|
||||
const WEBCONSOLE_STRINGS_URI = "chrome://devtools/locale/webconsole.properties";
|
||||
var L10N = new LocalizationHelper(NET_STRINGS_URI);
|
||||
const WEBCONSOLE_L10N = new LocalizationHelper(WEBCONSOLE_STRINGS_URI);
|
||||
|
||||
// ms
|
||||
const WDA_DEFAULT_VERIFY_INTERVAL = 50;
|
||||
|
@ -63,8 +61,6 @@ const RESIZE_REFRESH_RATE = 50;
|
|||
// ms
|
||||
const REQUESTS_REFRESH_RATE = 50;
|
||||
const REQUESTS_TOOLTIP_POSITION = "topcenter bottomleft";
|
||||
// tooltip show/hide delay in ms
|
||||
const REQUESTS_TOOLTIP_TOGGLE_DELAY = 500;
|
||||
// px
|
||||
const REQUESTS_TOOLTIP_IMAGE_MAX_DIM = 400;
|
||||
// px
|
||||
|
@ -106,31 +102,6 @@ const CONTENT_MIME_TYPE_MAPPINGS = {
|
|||
"/rss": Editor.modes.css,
|
||||
"/css": Editor.modes.css
|
||||
};
|
||||
const LOAD_CAUSE_STRINGS = {
|
||||
[Ci.nsIContentPolicy.TYPE_INVALID]: "invalid",
|
||||
[Ci.nsIContentPolicy.TYPE_OTHER]: "other",
|
||||
[Ci.nsIContentPolicy.TYPE_SCRIPT]: "script",
|
||||
[Ci.nsIContentPolicy.TYPE_IMAGE]: "img",
|
||||
[Ci.nsIContentPolicy.TYPE_STYLESHEET]: "stylesheet",
|
||||
[Ci.nsIContentPolicy.TYPE_OBJECT]: "object",
|
||||
[Ci.nsIContentPolicy.TYPE_DOCUMENT]: "document",
|
||||
[Ci.nsIContentPolicy.TYPE_SUBDOCUMENT]: "subdocument",
|
||||
[Ci.nsIContentPolicy.TYPE_REFRESH]: "refresh",
|
||||
[Ci.nsIContentPolicy.TYPE_XBL]: "xbl",
|
||||
[Ci.nsIContentPolicy.TYPE_PING]: "ping",
|
||||
[Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST]: "xhr",
|
||||
[Ci.nsIContentPolicy.TYPE_OBJECT_SUBREQUEST]: "objectSubdoc",
|
||||
[Ci.nsIContentPolicy.TYPE_DTD]: "dtd",
|
||||
[Ci.nsIContentPolicy.TYPE_FONT]: "font",
|
||||
[Ci.nsIContentPolicy.TYPE_MEDIA]: "media",
|
||||
[Ci.nsIContentPolicy.TYPE_WEBSOCKET]: "websocket",
|
||||
[Ci.nsIContentPolicy.TYPE_CSP_REPORT]: "csp",
|
||||
[Ci.nsIContentPolicy.TYPE_XSLT]: "xslt",
|
||||
[Ci.nsIContentPolicy.TYPE_BEACON]: "beacon",
|
||||
[Ci.nsIContentPolicy.TYPE_FETCH]: "fetch",
|
||||
[Ci.nsIContentPolicy.TYPE_IMAGESET]: "imageset",
|
||||
[Ci.nsIContentPolicy.TYPE_WEB_MANIFEST]: "webManifest"
|
||||
};
|
||||
const DEFAULT_EDITOR_CONFIG = {
|
||||
mode: Editor.modes.text,
|
||||
readOnly: true,
|
||||
|
@ -460,20 +431,6 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
this.userInputTimer = Cc["@mozilla.org/timer;1"]
|
||||
.createInstance(Ci.nsITimer);
|
||||
|
||||
// Create a tooltip for the newly appended network request item.
|
||||
this.tooltip = new Tooltip(document, {
|
||||
closeOnEvents: [{
|
||||
emitter: $("#requests-menu-contents"),
|
||||
event: "scroll",
|
||||
useCapture: true
|
||||
}]
|
||||
});
|
||||
this.tooltip.startTogglingOnHover(this.widget, this._onHover, {
|
||||
toggleDelay: REQUESTS_TOOLTIP_TOGGLE_DELAY,
|
||||
interactive: true
|
||||
});
|
||||
this.tooltip.defaultPosition = REQUESTS_TOOLTIP_POSITION;
|
||||
|
||||
Prefs.filters.forEach(type => this.filterOn(type));
|
||||
this.sortContents(this._byTiming);
|
||||
|
||||
|
@ -680,20 +637,15 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
* Specifies the request's url.
|
||||
* @param boolean isXHR
|
||||
* True if this request was initiated via XHR.
|
||||
* @param object cause
|
||||
* Specifies the request's cause. Has the following properties:
|
||||
* - type: nsContentPolicyType constant
|
||||
* - loadingDocumentUri: URI of the request origin
|
||||
* - stacktrace: JS stacktrace of the request
|
||||
* @param boolean fromCache
|
||||
* Indicates if the result came from the browser cache
|
||||
* @param boolean fromServiceWorker
|
||||
* Indicates if the request has been intercepted by a Service Worker
|
||||
*/
|
||||
addRequest: function (id, startedDateTime, method, url, isXHR, cause,
|
||||
fromCache, fromServiceWorker) {
|
||||
this._addQueue.push([id, startedDateTime, method, url, isXHR, cause,
|
||||
fromCache, fromServiceWorker]);
|
||||
addRequest: function (id, startedDateTime, method, url, isXHR, fromCache,
|
||||
fromServiceWorker) {
|
||||
this._addQueue.push([id, startedDateTime, method, url, isXHR, fromCache,
|
||||
fromServiceWorker]);
|
||||
|
||||
// Lazy updating is disabled in some tests.
|
||||
if (!this.lazyUpdate) {
|
||||
|
@ -933,8 +885,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
let selected = this.selectedItem.attachment;
|
||||
|
||||
// Create the element node for the network request item.
|
||||
let menuView = this._createMenuView(selected.method, selected.url,
|
||||
selected.cause);
|
||||
let menuView = this._createMenuView(selected.method, selected.url);
|
||||
|
||||
// Append a network request item to this container.
|
||||
let newItem = this.push([menuView], {
|
||||
|
@ -1500,6 +1451,19 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Refreshes the toggling anchor for the specified item's tooltip.
|
||||
*
|
||||
* @param object item
|
||||
* The network request item in this container.
|
||||
*/
|
||||
refreshTooltip: function (item) {
|
||||
let tooltip = item.attachment.tooltip;
|
||||
tooltip.hide();
|
||||
tooltip.startTogglingOnHover(item.target, this._onHover);
|
||||
tooltip.defaultPosition = REQUESTS_TOOLTIP_POSITION;
|
||||
},
|
||||
|
||||
/**
|
||||
* Attaches security icon click listener for the given request menu item.
|
||||
*
|
||||
|
@ -1546,13 +1510,13 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
let widget = NetMonitorView.RequestsMenu.widget;
|
||||
let isScrolledToBottom = widget.isScrolledToBottom();
|
||||
|
||||
for (let [id, startedDateTime, method, url, isXHR, cause, fromCache,
|
||||
for (let [id, startedDateTime, method, url, isXHR, fromCache,
|
||||
fromServiceWorker] of this._addQueue) {
|
||||
// Convert the received date/time string to a unix timestamp.
|
||||
let unixTime = Date.parse(startedDateTime);
|
||||
|
||||
// Create the element node for the network request item.
|
||||
let menuView = this._createMenuView(method, url, cause);
|
||||
let menuView = this._createMenuView(method, url);
|
||||
|
||||
// Remember the first and last event boundaries.
|
||||
this._registerFirstRequestStart(unixTime);
|
||||
|
@ -1566,12 +1530,22 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
method: method,
|
||||
url: url,
|
||||
isXHR: isXHR,
|
||||
cause: cause,
|
||||
fromCache: fromCache,
|
||||
fromServiceWorker: fromServiceWorker
|
||||
}
|
||||
});
|
||||
|
||||
// Create a tooltip for the newly appended network request item.
|
||||
requestItem.attachment.tooltip = new Tooltip(document, {
|
||||
closeOnEvents: [{
|
||||
emitter: $("#requests-menu-contents"),
|
||||
event: "scroll",
|
||||
useCapture: true
|
||||
}]
|
||||
});
|
||||
|
||||
this.refreshTooltip(requestItem);
|
||||
|
||||
if (id == this._preferredItemId) {
|
||||
this.selectedItem = requestItem;
|
||||
}
|
||||
|
@ -1780,26 +1754,21 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
* Specifies the request method (e.g. "GET", "POST", etc.)
|
||||
* @param string url
|
||||
* Specifies the request's url.
|
||||
* @param object cause
|
||||
* Specifies the request's cause. Has two properties:
|
||||
* - type: nsContentPolicyType constant
|
||||
* - uri: URI of the request origin
|
||||
* @return nsIDOMNode
|
||||
* The network request view.
|
||||
*/
|
||||
_createMenuView: function (method, url, cause) {
|
||||
_createMenuView: function (method, url) {
|
||||
let template = $("#requests-menu-item-template");
|
||||
let fragment = document.createDocumentFragment();
|
||||
|
||||
this.updateMenuView(template, "method", method);
|
||||
this.updateMenuView(template, "url", url);
|
||||
|
||||
// Flatten the DOM by removing one redundant box (the template container).
|
||||
for (let node of template.childNodes) {
|
||||
fragment.appendChild(node.cloneNode(true));
|
||||
}
|
||||
|
||||
this.updateMenuView(fragment, "method", method);
|
||||
this.updateMenuView(fragment, "url", url);
|
||||
this.updateMenuView(fragment, "cause", cause);
|
||||
|
||||
return fragment;
|
||||
},
|
||||
|
||||
|
@ -1931,20 +1900,6 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
node.setAttribute("tooltiptext", value);
|
||||
break;
|
||||
}
|
||||
case "cause": {
|
||||
let labelNode = $(".requests-menu-cause-label", target);
|
||||
let text = LOAD_CAUSE_STRINGS[value.type] || "unknown";
|
||||
labelNode.setAttribute("value", text);
|
||||
if (value.loadingDocumentUri) {
|
||||
labelNode.setAttribute("tooltiptext", value.loadingDocumentUri);
|
||||
}
|
||||
|
||||
let stackNode = $(".requests-menu-cause-stack", target);
|
||||
if (value.stacktrace && value.stacktrace.length > 0) {
|
||||
stackNode.removeAttribute("hidden");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "contentSize": {
|
||||
let node = $(".requests-menu-size", target);
|
||||
|
||||
|
@ -2275,6 +2230,11 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
* Called when two items switch places, when the contents are sorted.
|
||||
*/
|
||||
_onSwap: function ({ detail: [firstItem, secondItem] }) {
|
||||
// Sorting will create new anchor nodes for all the swapped request items
|
||||
// in this container, so it's necessary to refresh the Tooltip instances.
|
||||
this.refreshTooltip(firstItem);
|
||||
this.refreshTooltip(secondItem);
|
||||
|
||||
// Reattach click listener to the security icons
|
||||
this.attachSecurityIconClickListener(firstItem);
|
||||
this.attachSecurityIconClickListener(secondItem);
|
||||
|
@ -2292,92 +2252,28 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
*/
|
||||
_onHover: Task.async(function* (target, tooltip) {
|
||||
let requestItem = this.getItemForElement(target);
|
||||
if (!requestItem) {
|
||||
if (!requestItem || !requestItem.attachment.responseContent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let hovered = requestItem.attachment;
|
||||
if (hovered.responseContent && target.closest(".requests-menu-icon-and-file")) {
|
||||
return this._setTooltipImageContent(tooltip, requestItem);
|
||||
} else if (hovered.cause && target.closest(".requests-menu-cause-stack")) {
|
||||
return this._setTooltipStackTraceContent(tooltip, requestItem);
|
||||
}
|
||||
let { mimeType, text, encoding } = hovered.responseContent.content;
|
||||
|
||||
if (mimeType && mimeType.includes("image/") && (
|
||||
target.classList.contains("requests-menu-icon") ||
|
||||
target.classList.contains("requests-menu-file"))) {
|
||||
let string = yield gNetwork.getString(text);
|
||||
let anchor = $(".requests-menu-icon", requestItem.target);
|
||||
let src = formDataURI(mimeType, encoding, string);
|
||||
|
||||
tooltip.setImageContent(src, {
|
||||
maxDim: REQUESTS_TOOLTIP_IMAGE_MAX_DIM
|
||||
});
|
||||
return anchor;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
|
||||
_setTooltipImageContent: Task.async(function* (tooltip, requestItem) {
|
||||
let { mimeType, text, encoding } = requestItem.attachment.responseContent.content;
|
||||
|
||||
if (!mimeType || !mimeType.includes("image/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let string = yield gNetwork.getString(text);
|
||||
let anchor = $(".requests-menu-icon", requestItem.target);
|
||||
let src = formDataURI(mimeType, encoding, string);
|
||||
|
||||
tooltip.setImageContent(src, {
|
||||
maxDim: REQUESTS_TOOLTIP_IMAGE_MAX_DIM
|
||||
});
|
||||
|
||||
return anchor;
|
||||
}),
|
||||
|
||||
_setTooltipStackTraceContent: Task.async(function* (tooltip, requestItem) {
|
||||
let {stacktrace} = requestItem.attachment.cause;
|
||||
|
||||
if (!stacktrace || stacktrace.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let doc = tooltip.doc;
|
||||
let el = doc.createElement("vbox");
|
||||
el.className = "requests-menu-stack-trace";
|
||||
|
||||
for (let f of stacktrace) {
|
||||
let { functionName, filename, lineNumber, columnNumber } = f;
|
||||
|
||||
let frameEl = doc.createElement("hbox");
|
||||
frameEl.className = "requests-menu-stack-frame devtools-monospace";
|
||||
|
||||
let funcEl = doc.createElement("label");
|
||||
funcEl.className = "requests-menu-stack-frame-function-name";
|
||||
funcEl.setAttribute("value",
|
||||
functionName || WEBCONSOLE_L10N.getStr("stacktrace.anonymousFunction"));
|
||||
frameEl.appendChild(funcEl);
|
||||
|
||||
let fileEl = doc.createElement("label");
|
||||
fileEl.className = "requests-menu-stack-frame-file-name";
|
||||
// Parse a stack frame in format "url -> url"
|
||||
let sourceUrl = filename.split(" -> ").pop();
|
||||
fileEl.setAttribute("value", sourceUrl);
|
||||
fileEl.setAttribute("tooltiptext", sourceUrl);
|
||||
fileEl.setAttribute("crop", "start");
|
||||
frameEl.appendChild(fileEl);
|
||||
|
||||
let lineEl = doc.createElement("label");
|
||||
lineEl.className = "requests-menu-stack-frame-line";
|
||||
lineEl.setAttribute("value", `:${lineNumber}:${columnNumber}`);
|
||||
frameEl.appendChild(lineEl);
|
||||
|
||||
frameEl.addEventListener("click", () => {
|
||||
// avoid an ugly visual artefact when the view is switched to debugger and the
|
||||
// tooltip is hidden only after a delay - the tooltip is moved outside the browser
|
||||
// window.
|
||||
tooltip.hide();
|
||||
NetMonitorController.viewSourceInDebugger(filename, lineNumber);
|
||||
}, false);
|
||||
|
||||
el.appendChild(frameEl);
|
||||
}
|
||||
|
||||
tooltip.content = el;
|
||||
tooltip.panel.setAttribute("wide", "");
|
||||
|
||||
return true;
|
||||
}),
|
||||
|
||||
/**
|
||||
* A handler that opens the security tab in the details view if secure or
|
||||
* broken security indicator is clicked.
|
||||
|
|
|
@ -221,17 +221,6 @@
|
|||
flex="1">
|
||||
</button>
|
||||
</hbox>
|
||||
<hbox id="requests-menu-cause-header-box"
|
||||
class="requests-menu-header requests-menu-cause"
|
||||
align="center">
|
||||
<button id="requests-menu-cause-button"
|
||||
class="requests-menu-header-button requests-menu-cause"
|
||||
data-key="cause"
|
||||
label="&netmonitorUI.toolbar.cause;"
|
||||
crop="end"
|
||||
flex="1">
|
||||
</button>
|
||||
</hbox>
|
||||
<hbox id="requests-menu-type-header-box"
|
||||
class="requests-menu-header requests-menu-type"
|
||||
align="center">
|
||||
|
@ -334,10 +323,6 @@
|
|||
crop="end"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
<hbox class="requests-menu-subitem requests-menu-cause" align="center">
|
||||
<label class="requests-menu-cause-stack" value="JS" hidden="true"/>
|
||||
<label class="plain requests-menu-cause-label" flex="1" crop="end"/>
|
||||
</hbox>
|
||||
<label class="plain requests-menu-subitem requests-menu-type"
|
||||
crop="end"/>
|
||||
<label class="plain requests-menu-subitem requests-menu-transferred"
|
||||
|
|
|
@ -16,7 +16,6 @@ function NetMonitorPanel(iframeWindow, toolbox) {
|
|||
this._view = this.panelWin.NetMonitorView;
|
||||
this._controller = this.panelWin.NetMonitorController;
|
||||
this._controller._target = this.target;
|
||||
this._controller._toolbox = this._toolbox;
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ subsuite = devtools
|
|||
support-files =
|
||||
dropmarker.svg
|
||||
head.js
|
||||
html_cause-test-page.html
|
||||
html_content-type-test-page.html
|
||||
html_content-type-without-cache-test-page.html
|
||||
html_cors-test-page.html
|
||||
|
@ -34,7 +33,6 @@ support-files =
|
|||
sjs_content-type-test-server.sjs
|
||||
sjs_cors-test-server.sjs
|
||||
sjs_https-redirect-test-server.sjs
|
||||
sjs_hsts-test-server.sjs
|
||||
sjs_simple-test-server.sjs
|
||||
sjs_sorting-test-server.sjs
|
||||
sjs_status-codes-test-server.sjs
|
||||
|
@ -49,8 +47,6 @@ skip-if = (toolkit == "cocoa" && e10s) # bug 1252254
|
|||
[browser_net_api-calls.js]
|
||||
[browser_net_autoscroll.js]
|
||||
[browser_net_cached-status.js]
|
||||
[browser_net_cause.js]
|
||||
[browser_net_cause_redirect.js]
|
||||
[browser_net_service-worker-status.js]
|
||||
[browser_net_charts-01.js]
|
||||
[browser_net_charts-02.js]
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if request cause is reported correctly.
|
||||
*/
|
||||
|
||||
const CAUSE_FILE_NAME = "html_cause-test-page.html";
|
||||
const CAUSE_URL = EXAMPLE_URL + CAUSE_FILE_NAME;
|
||||
|
||||
const EXPECTED_REQUESTS = [
|
||||
{
|
||||
method: "GET",
|
||||
url: CAUSE_URL,
|
||||
causeType: "document",
|
||||
causeUri: "",
|
||||
// The document load is from JS function in e10s, native in non-e10s
|
||||
hasStack: !gMultiProcessBrowser
|
||||
},
|
||||
{
|
||||
method: "GET",
|
||||
url: EXAMPLE_URL + "stylesheet_request",
|
||||
causeType: "stylesheet",
|
||||
causeUri: CAUSE_URL,
|
||||
hasStack: false
|
||||
},
|
||||
{
|
||||
method: "GET",
|
||||
url: EXAMPLE_URL + "img_request",
|
||||
causeType: "img",
|
||||
causeUri: CAUSE_URL,
|
||||
hasStack: false
|
||||
},
|
||||
{
|
||||
method: "GET",
|
||||
url: EXAMPLE_URL + "xhr_request",
|
||||
causeType: "xhr",
|
||||
causeUri: CAUSE_URL,
|
||||
hasStack: { fn: "performXhrRequest", file: CAUSE_FILE_NAME, line: 22 }
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
url: EXAMPLE_URL + "beacon_request",
|
||||
causeType: "beacon",
|
||||
causeUri: CAUSE_URL,
|
||||
hasStack: { fn: "performBeaconRequest", file: CAUSE_FILE_NAME, line: 26 }
|
||||
},
|
||||
];
|
||||
|
||||
var test = Task.async(function* () {
|
||||
// the initNetMonitor function clears the network request list after the
|
||||
// page is loaded. That's why we first load a bogus page from SIMPLE_URL,
|
||||
// and only then load the real thing from CAUSE_URL - we want to catch
|
||||
// all the requests the page is making, not only the XHRs.
|
||||
// We can't use about:blank here, because initNetMonitor checks that the
|
||||
// page has actually made at least one request.
|
||||
let [, debuggee, monitor] = yield initNetMonitor(SIMPLE_URL);
|
||||
let { RequestsMenu } = monitor.panelWin.NetMonitorView;
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
debuggee.location = CAUSE_URL;
|
||||
|
||||
yield waitForNetworkEvents(monitor, EXPECTED_REQUESTS.length);
|
||||
|
||||
is(RequestsMenu.itemCount, EXPECTED_REQUESTS.length,
|
||||
"All the page events should be recorded.");
|
||||
|
||||
EXPECTED_REQUESTS.forEach((spec, i) => {
|
||||
let { method, url, causeType, causeUri, hasStack } = spec;
|
||||
|
||||
let requestItem = RequestsMenu.getItemAtIndex(i);
|
||||
verifyRequestItemTarget(requestItem,
|
||||
method, url, { cause: { type: causeType, loadingDocumentUri: causeUri } }
|
||||
);
|
||||
|
||||
let { stacktrace } = requestItem.attachment.cause;
|
||||
let stackLen = stacktrace ? stacktrace.length : 0;
|
||||
|
||||
if (hasStack) {
|
||||
ok(stacktrace, `Request #${i} has a stacktrace`);
|
||||
ok(stackLen > 0,
|
||||
`Request #${i} (${causeType}) has a stacktrace with ${stackLen} items`);
|
||||
|
||||
// if "hasStack" is object, check the details about the top stack frame
|
||||
if (typeof hasStack === "object") {
|
||||
is(stacktrace[0].functionName, hasStack.fn,
|
||||
`Request #${i} has the correct function on top of the JS stack`);
|
||||
is(stacktrace[0].filename.split("/").pop(), hasStack.file,
|
||||
`Request #${i} has the correct file on top of the JS stack`);
|
||||
is(stacktrace[0].lineNumber, hasStack.line,
|
||||
`Request #${i} has the correct line number on top of the JS stack`);
|
||||
}
|
||||
} else {
|
||||
is(stackLen, 0, `Request #${i} (${causeType}) has an empty stacktrace`);
|
||||
}
|
||||
});
|
||||
|
||||
yield teardown(monitor);
|
||||
finish();
|
||||
});
|
|
@ -1,50 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if request JS stack is property reported if the request is internally
|
||||
* redirected without hitting the network (HSTS is one of such cases)
|
||||
*/
|
||||
|
||||
var test = Task.async(function* () {
|
||||
const EXPECTED_REQUESTS = [
|
||||
// Request to HTTP URL, redirects to HTTPS, has callstack
|
||||
{ status: 302, hasStack: true },
|
||||
// Serves HTTPS, sets the Strict-Transport-Security header, no stack
|
||||
{ status: 200, hasStack: false },
|
||||
// Second request to HTTP redirects to HTTPS internally
|
||||
{ status: 200, hasStack: true },
|
||||
];
|
||||
|
||||
let [, debuggee, monitor] = yield initNetMonitor(CUSTOM_GET_URL);
|
||||
let { RequestsMenu } = monitor.panelWin.NetMonitorView;
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
debuggee.performRequests(2, HSTS_SJS);
|
||||
yield waitForNetworkEvents(monitor, EXPECTED_REQUESTS.length);
|
||||
|
||||
EXPECTED_REQUESTS.forEach(({status, hasStack}, i) => {
|
||||
let { attachment } = RequestsMenu.getItemAtIndex(i);
|
||||
|
||||
is(attachment.status, status, `Request #${i} has the expected status`);
|
||||
|
||||
let { stacktrace } = attachment.cause;
|
||||
let stackLen = stacktrace ? stacktrace.length : 0;
|
||||
|
||||
if (hasStack) {
|
||||
ok(stacktrace, `Request #${i} has a stacktrace`);
|
||||
ok(stackLen > 0, `Request #${i} has a stacktrace with ${stackLen} items`);
|
||||
} else {
|
||||
is(stackLen, 0, `Request #${i} has an empty stacktrace`);
|
||||
}
|
||||
});
|
||||
|
||||
// Send a request to reset the HSTS policy to state before the test
|
||||
debuggee.performRequests(1, HSTS_SJS + "?reset");
|
||||
yield waitForNetworkEvents(monitor, 1);
|
||||
|
||||
yield teardown(monitor);
|
||||
finish();
|
||||
});
|
|
@ -23,7 +23,7 @@ add_task(function* test() {
|
|||
yield onThumbnail;
|
||||
|
||||
info("Checking the image thumbnail after a few requests were made...");
|
||||
yield showTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.items[5]);
|
||||
yield showTooltipAndVerify(RequestsMenu.items[5]);
|
||||
|
||||
// 7 XHRs as before + 1 extra document reload
|
||||
onEvents = waitForNetworkEvents(monitor, 8);
|
||||
|
@ -36,7 +36,7 @@ add_task(function* test() {
|
|||
yield onThumbnail;
|
||||
|
||||
info("Checking the image thumbnail after a reload.");
|
||||
yield showTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.items[6]);
|
||||
yield showTooltipAndVerify(RequestsMenu.items[6]);
|
||||
|
||||
yield teardown(monitor);
|
||||
finish();
|
||||
|
@ -45,7 +45,10 @@ add_task(function* test() {
|
|||
* Show a tooltip on the {requestItem} and verify that it was displayed
|
||||
* with the expected content.
|
||||
*/
|
||||
function* showTooltipAndVerify(tooltip, requestItem) {
|
||||
function* showTooltipAndVerify(requestItem) {
|
||||
let { tooltip } = requestItem.attachment;
|
||||
ok(tooltip, "There should be a tooltip instance for the image request.");
|
||||
|
||||
let anchor = $(".requests-menu-file", requestItem.target);
|
||||
yield showTooltipOn(tooltip, anchor);
|
||||
|
||||
|
|
|
@ -13,11 +13,11 @@ const URL = EXAMPLE_URL.replace("http:", "https:");
|
|||
const TEST_URL = URL + "service-workers/status-codes.html";
|
||||
|
||||
var test = Task.async(function* () {
|
||||
let [, debuggee, monitor] = yield initNetMonitor(TEST_URL, null, true);
|
||||
let [tab, debuggee, monitor] = yield initNetMonitor(TEST_URL, null, true);
|
||||
info("Starting test... ");
|
||||
|
||||
let { NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
let { document, L10N, NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu, NetworkDetails } = NetMonitorView;
|
||||
|
||||
const REQUEST_DATA = [
|
||||
{
|
||||
|
@ -29,8 +29,7 @@ var test = Task.async(function* () {
|
|||
displayedStatus: "service worker",
|
||||
type: "plain",
|
||||
fullMimeType: "text/plain; charset=UTF-8"
|
||||
},
|
||||
stackFunctions: ["doXHR", "performRequests"]
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -45,27 +44,12 @@ var test = Task.async(function* () {
|
|||
for (let request of REQUEST_DATA) {
|
||||
let item = RequestsMenu.getItemAtIndex(index);
|
||||
|
||||
info(`Verifying request #${index}`);
|
||||
info("Verifying request #" + index);
|
||||
yield verifyRequestItemTarget(item, request.method, request.uri, request.details);
|
||||
|
||||
let { stacktrace } = item.attachment.cause;
|
||||
let stackLen = stacktrace ? stacktrace.length : 0;
|
||||
|
||||
ok(stacktrace, `Request #${index} has a stacktrace`);
|
||||
ok(stackLen >= request.stackFunctions.length,
|
||||
`Request #${index} has a stacktrace with enough (${stackLen}) items`);
|
||||
|
||||
request.stackFunctions.forEach((functionName, j) => {
|
||||
is(stacktrace[j].functionName, functionName,
|
||||
`Request #${index} has the correct function at position #${j} on the stack`);
|
||||
});
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
info("Unregistering the service worker...");
|
||||
yield debuggee.unregisterServiceWorker();
|
||||
|
||||
yield teardown(monitor);
|
||||
finish();
|
||||
});
|
||||
|
|
|
@ -50,10 +50,6 @@ const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
|
|||
const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
|
||||
const HTTPS_REDIRECT_SJS = EXAMPLE_URL + "sjs_https-redirect-test-server.sjs";
|
||||
const CORS_SJS_PATH = "/browser/devtools/client/netmonitor/test/sjs_cors-test-server.sjs";
|
||||
const HSTS_SJS = EXAMPLE_URL + "sjs_hsts-test-server.sjs";
|
||||
|
||||
const HSTS_BASE_URL = EXAMPLE_URL;
|
||||
const HSTS_PAGE_URL = CUSTOM_GET_URL;
|
||||
|
||||
const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
|
||||
const TEST_IMAGE_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
|
||||
|
@ -288,7 +284,7 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
|
|||
info("Widget index of item: " + widgetIndex);
|
||||
info("Visible index of item: " + visibleIndex);
|
||||
|
||||
let { fuzzyUrl, status, statusText, cause, type, fullMimeType,
|
||||
let { fuzzyUrl, status, statusText, type, fullMimeType,
|
||||
transferred, size, time, displayedStatus } = aData;
|
||||
let { attachment, target } = aRequestItem;
|
||||
|
||||
|
@ -340,15 +336,6 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
|
|||
is(codeValue, status, "The displayed status code is correct.");
|
||||
is(tooltip, status + " " + statusText, "The tooltip status is correct.");
|
||||
}
|
||||
if (cause !== undefined) {
|
||||
let causeLabel = target.querySelector(".requests-menu-cause-label");
|
||||
let value = causeLabel.getAttribute("value");
|
||||
let tooltip = causeLabel.getAttribute("tooltiptext");
|
||||
info("Displayed cause: " + value);
|
||||
info("Tooltip cause: " + tooltip);
|
||||
is(value, cause.type, "The displayed cause is correct.");
|
||||
is(tooltip, cause.loadingDocumentUri, "The tooltip cause is correct.")
|
||||
}
|
||||
if (type !== undefined) {
|
||||
let value = target.querySelector(".requests-menu-type").getAttribute("value");
|
||||
let tooltip = target.querySelector(".requests-menu-type").getAttribute("tooltiptext");
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<title>Network Monitor test page</title>
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet_request" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Request cause test</p>
|
||||
<img src="img_request" />
|
||||
<script type="text/javascript">
|
||||
function performXhrRequest() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "xhr_request", true);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function performBeaconRequest() {
|
||||
navigator.sendBeacon("beacon_request");
|
||||
}
|
||||
|
||||
performXhrRequest();
|
||||
performBeaconRequest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -2,14 +2,7 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
self.addEventListener("activate", event => {
|
||||
// start controlling the already loaded page
|
||||
event.waitUntil(self.clients.claim());
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", event => {
|
||||
addEventListener("fetch", function (event) {
|
||||
let response = new Response("Service worker response");
|
||||
event.respondWith(response);
|
||||
});
|
||||
|
|
|
@ -15,44 +15,24 @@
|
|||
<p>Status codes test</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
let swRegistration;
|
||||
|
||||
function registerServiceWorker() {
|
||||
let sw = navigator.serviceWorker;
|
||||
return sw.register("status-codes-service-worker.js")
|
||||
.then(registration => {
|
||||
swRegistration = registration;
|
||||
console.log("Registered, scope is:", registration.scope);
|
||||
return sw.ready;
|
||||
}).then(() => {
|
||||
// wait until the page is controlled
|
||||
return new Promise(resolve => {
|
||||
if (sw.controller) {
|
||||
resolve();
|
||||
} else {
|
||||
sw.addEventListener('controllerchange', function onControllerChange() {
|
||||
sw.removeEventListener('controllerchange', onControllerChange);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error("Registration failed");
|
||||
});
|
||||
function get(url) {
|
||||
return new Promise(done => {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("src", url);
|
||||
document.documentElement.appendChild(iframe);
|
||||
iframe.contentWindow.onload = done;
|
||||
});
|
||||
}
|
||||
|
||||
function unregisterServiceWorker() {
|
||||
return swRegistration.unregister();
|
||||
function registerServiceWorker() {
|
||||
return navigator.serviceWorker.register("status-codes-service-worker.js")
|
||||
.then(() => navigator.serviceWorker.ready);
|
||||
}
|
||||
|
||||
function performRequests() {
|
||||
return new Promise(function doXHR(done) {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "test/200", true);
|
||||
xhr.onreadystatechange = done;
|
||||
xhr.send(null);
|
||||
});
|
||||
return get("test/200");
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
|
||||
if (request.queryString === "reset") {
|
||||
// Reset the HSTS policy, prevent influencing other tests
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Strict-Transport-Security", "max-age=0");
|
||||
response.write("Resetting HSTS");
|
||||
} else if (request.scheme === "http") {
|
||||
response.setStatusLine(request.httpVersion, 302, "Found");
|
||||
response.setHeader("Location", "https://" + request.host + request.path);
|
||||
} else {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Strict-Transport-Security", "max-age=100");
|
||||
response.write("Page was accessed over HTTPS!");
|
||||
}
|
||||
}
|
|
@ -246,25 +246,6 @@
|
|||
width: 8vw;
|
||||
}
|
||||
|
||||
.requests-menu-cause {
|
||||
max-width: 8em;
|
||||
width: 8vw;
|
||||
}
|
||||
|
||||
.requests-menu-cause-stack {
|
||||
background-color: var(--theme-body-color-alt);
|
||||
color: var(--theme-body-background);
|
||||
font-size: 8px;
|
||||
font-weight: bold;
|
||||
line-height: 10px;
|
||||
border-radius: 3px;
|
||||
padding: 0 2px;
|
||||
margin: 0;
|
||||
margin-inline-end: 3px;
|
||||
-moz-user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.requests-menu-transferred {
|
||||
max-width: 8em;
|
||||
text-align: center;
|
||||
|
@ -695,40 +676,6 @@
|
|||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
/* Requests menu stacktrace tooltip */
|
||||
.requests-menu-stack-trace {
|
||||
max-height: 400px;
|
||||
width: 586px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.requests-menu-stack-frame {
|
||||
color: var(--theme-body-color-alt);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.requests-menu-stack-frame:hover {
|
||||
background-color: var(--theme-selection-background-semitransparent);
|
||||
}
|
||||
|
||||
.requests-menu-stack-frame-function-name {
|
||||
color: var(--theme-highlight-blue);
|
||||
cursor: inherit;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.requests-menu-stack-frame-file-name {
|
||||
cursor: inherit;
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
|
||||
.requests-menu-stack-frame-line {
|
||||
color: var(--theme-highlight-orange);
|
||||
cursor: inherit;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
/* Performance analysis buttons */
|
||||
|
||||
#requests-menu-network-summary-button {
|
||||
|
|
|
@ -18,7 +18,6 @@ const ErrorDocs = require("devtools/server/actors/errordocs");
|
|||
loader.lazyRequireGetter(this, "NetworkMonitor", "devtools/shared/webconsole/network-monitor", true);
|
||||
loader.lazyRequireGetter(this, "NetworkMonitorChild", "devtools/shared/webconsole/network-monitor", true);
|
||||
loader.lazyRequireGetter(this, "ConsoleProgressListener", "devtools/shared/webconsole/network-monitor", true);
|
||||
loader.lazyRequireGetter(this, "StackTraceCollector", "devtools/shared/webconsole/network-monitor", true);
|
||||
loader.lazyRequireGetter(this, "events", "sdk/event/core");
|
||||
loader.lazyRequireGetter(this, "ServerLoggingListener", "devtools/shared/webconsole/server-logger", true);
|
||||
loader.lazyRequireGetter(this, "JSPropertyProvider", "devtools/shared/webconsole/js-property-provider", true);
|
||||
|
@ -599,12 +598,6 @@ WebConsoleActor.prototype =
|
|||
break;
|
||||
case "NetworkActivity":
|
||||
if (!this.networkMonitor) {
|
||||
// Create a StackTraceCollector that's going to be shared both by the
|
||||
// NetworkMonitorChild (getting messages about requests from parent) and
|
||||
// by the NetworkMonitor that directly watches service workers requests.
|
||||
this.stackTraceCollector = new StackTraceCollector({ window, appId });
|
||||
this.stackTraceCollector.init();
|
||||
|
||||
if (appId || messageManager) {
|
||||
// Start a network monitor in the parent process to listen to
|
||||
// most requests than happen in parent
|
||||
|
@ -613,10 +606,12 @@ WebConsoleActor.prototype =
|
|||
this.parentActor.actorID, this);
|
||||
this.networkMonitor.init();
|
||||
// Spawn also one in the child to listen to service workers
|
||||
this.networkMonitorChild = new NetworkMonitor({ window }, this);
|
||||
this.networkMonitorChild = new NetworkMonitor({ window: window },
|
||||
this);
|
||||
this.networkMonitorChild.init();
|
||||
} else {
|
||||
this.networkMonitor = new NetworkMonitor({ window }, this);
|
||||
}
|
||||
else {
|
||||
this.networkMonitor = new NetworkMonitor({ window: window }, this);
|
||||
this.networkMonitor.init();
|
||||
}
|
||||
}
|
||||
|
@ -705,10 +700,6 @@ WebConsoleActor.prototype =
|
|||
this.networkMonitorChild.destroy();
|
||||
this.networkMonitorChild = null;
|
||||
}
|
||||
if (this.stackTraceCollector) {
|
||||
this.stackTraceCollector.destroy();
|
||||
this.stackTraceCollector = null;
|
||||
}
|
||||
stoppedListeners.push(listener);
|
||||
break;
|
||||
case "FileActivity":
|
||||
|
@ -1837,7 +1828,6 @@ NetworkEventActor.prototype =
|
|||
url: this._request.url,
|
||||
method: this._request.method,
|
||||
isXHR: this._isXHR,
|
||||
cause: this._cause,
|
||||
fromCache: this._fromCache,
|
||||
fromServiceWorker: this._fromServiceWorker,
|
||||
private: this._private,
|
||||
|
@ -1883,7 +1873,6 @@ NetworkEventActor.prototype =
|
|||
{
|
||||
this._startedDateTime = aNetworkEvent.startedDateTime;
|
||||
this._isXHR = aNetworkEvent.isXHR;
|
||||
this._cause = aNetworkEvent.cause;
|
||||
this._fromCache = aNetworkEvent.fromCache;
|
||||
this._fromServiceWorker = aNetworkEvent.fromServiceWorker;
|
||||
|
||||
|
|
|
@ -100,7 +100,6 @@ WebConsoleClient.prototype = {
|
|||
method: actor.method,
|
||||
},
|
||||
isXHR: actor.isXHR,
|
||||
cause: actor.cause,
|
||||
response: {},
|
||||
timings: {},
|
||||
// track the list of network event updates
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cm, Cu, Cr, components} = require("chrome");
|
||||
const {Cc, Ci, Cu, Cr} = require("chrome");
|
||||
const Services = require("Services");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
@ -36,236 +36,6 @@ const HTTP_TEMPORARY_REDIRECT = 307;
|
|||
// The maximum number of bytes a NetworkResponseListener can hold: 1 MB
|
||||
const RESPONSE_BODY_LIMIT = 1048576;
|
||||
|
||||
/**
|
||||
* Check if a given network request should be logged by a network monitor
|
||||
* based on the specified filters.
|
||||
*
|
||||
* @param nsIHttpChannel channel
|
||||
* Request to check.
|
||||
* @param filters
|
||||
* NetworkMonitor filters to match against.
|
||||
* @return boolean
|
||||
* True if the network request should be logged, false otherwise.
|
||||
*/
|
||||
function matchRequest(channel, filters) {
|
||||
// Log everything if no filter is specified
|
||||
if (!filters.topFrame && !filters.window && !filters.appId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ignore requests from chrome or add-on code when we are monitoring
|
||||
// content.
|
||||
// TODO: one particular test (browser_styleeditor_fetch-from-cache.js) needs
|
||||
// the DevToolsUtils.testing check. We will move to a better way to serve
|
||||
// its needs in bug 1167188, where this check should be removed.
|
||||
if (!DevToolsUtils.testing && channel.loadInfo &&
|
||||
channel.loadInfo.loadingDocument === null &&
|
||||
channel.loadInfo.loadingPrincipal ===
|
||||
Services.scriptSecurityManager.getSystemPrincipal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filters.window) {
|
||||
// Since frames support, this.window may not be the top level content
|
||||
// frame, so that we can't only compare with win.top.
|
||||
let win = NetworkHelper.getWindowForRequest(channel);
|
||||
while (win) {
|
||||
if (win == filters.window) {
|
||||
return true;
|
||||
}
|
||||
if (win.parent == win) {
|
||||
break;
|
||||
}
|
||||
win = win.parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (filters.topFrame) {
|
||||
let topFrame = NetworkHelper.getTopFrameForRequest(channel);
|
||||
if (topFrame && topFrame === filters.topFrame) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (filters.appId) {
|
||||
let appId = NetworkHelper.getAppIdForRequest(channel);
|
||||
if (appId && appId == filters.appId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// The following check is necessary because beacon channels don't come
|
||||
// associated with a load group. Bug 1160837 will hopefully introduce a
|
||||
// platform fix that will render the following code entirely useless.
|
||||
if (channel.loadInfo &&
|
||||
channel.loadInfo.externalContentPolicyType ==
|
||||
Ci.nsIContentPolicy.TYPE_BEACON) {
|
||||
let nonE10sMatch = filters.window &&
|
||||
channel.loadInfo.loadingDocument === filters.window.document;
|
||||
const loadingPrincipal = channel.loadInfo.loadingPrincipal;
|
||||
let e10sMatch = filters.topFrame &&
|
||||
filters.topFrame.contentPrincipal &&
|
||||
filters.topFrame.contentPrincipal.equals(loadingPrincipal) &&
|
||||
filters.topFrame.contentPrincipal.URI.spec == channel.referrer.spec;
|
||||
let b2gMatch = filters.appId && loadingPrincipal.appId === filters.appId;
|
||||
if (nonE10sMatch || e10sMatch || b2gMatch) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a nsIChannelEventSink implementation that monitors channel redirects and
|
||||
* informs the registered StackTraceCollector about the old and new channels.
|
||||
*/
|
||||
const SINK_CLASS_DESCRIPTION = "NetworkMonitor Channel Event Sink";
|
||||
const SINK_CLASS_ID = components.ID("{e89fa076-c845-48a8-8c45-2604729eba1d}");
|
||||
const SINK_CONTRACT_ID = "@mozilla.org/network/monitor/channeleventsink;1";
|
||||
const SINK_CATEGORY_NAME = "net-channel-event-sinks";
|
||||
|
||||
function ChannelEventSink() {
|
||||
this.wrappedJSObject = this;
|
||||
this.collectors = new Set();
|
||||
}
|
||||
|
||||
ChannelEventSink.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannelEventSink]),
|
||||
|
||||
registerCollector(collector) {
|
||||
this.collectors.add(collector);
|
||||
},
|
||||
|
||||
unregisterCollector(collector) {
|
||||
this.collectors.delete(collector);
|
||||
|
||||
if (this.collectors.size == 0) {
|
||||
ChannelEventSinkFactory.unregister();
|
||||
}
|
||||
},
|
||||
|
||||
asyncOnChannelRedirect(oldChannel, newChannel, flags, callback) {
|
||||
for (let collector of this.collectors) {
|
||||
try {
|
||||
collector.onChannelRedirect(oldChannel, newChannel, flags);
|
||||
} catch (ex) {
|
||||
console.error("StackTraceCollector.onChannelRedirect threw an exception", ex);
|
||||
}
|
||||
}
|
||||
callback.onRedirectVerifyCallback(Cr.NS_OK);
|
||||
}
|
||||
};
|
||||
|
||||
const ChannelEventSinkFactory = XPCOMUtils.generateSingletonFactory(ChannelEventSink);
|
||||
|
||||
ChannelEventSinkFactory.register = function () {
|
||||
const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
if (registrar.isCIDRegistered(SINK_CLASS_ID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
registrar.registerFactory(SINK_CLASS_ID,
|
||||
SINK_CLASS_DESCRIPTION,
|
||||
SINK_CONTRACT_ID,
|
||||
ChannelEventSinkFactory);
|
||||
|
||||
XPCOMUtils.categoryManager.addCategoryEntry(SINK_CATEGORY_NAME, SINK_CONTRACT_ID,
|
||||
SINK_CONTRACT_ID, false, true);
|
||||
};
|
||||
|
||||
ChannelEventSinkFactory.unregister = function () {
|
||||
const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.unregisterFactory(SINK_CLASS_ID, ChannelEventSinkFactory);
|
||||
|
||||
XPCOMUtils.categoryManager.deleteCategoryEntry(SINK_CATEGORY_NAME, SINK_CONTRACT_ID,
|
||||
false);
|
||||
};
|
||||
|
||||
ChannelEventSinkFactory.getService = function () {
|
||||
// Make sure the ChannelEventSink service is registered before accessing it
|
||||
ChannelEventSinkFactory.register();
|
||||
|
||||
return Cc[SINK_CONTRACT_ID].getService(Ci.nsIChannelEventSink).wrappedJSObject;
|
||||
};
|
||||
|
||||
function StackTraceCollector(filters) {
|
||||
this.filters = filters;
|
||||
this.stacktracesById = new Map();
|
||||
}
|
||||
|
||||
StackTraceCollector.prototype = {
|
||||
init() {
|
||||
Services.obs.addObserver(this, "http-on-opening-request", false);
|
||||
ChannelEventSinkFactory.getService().registerCollector(this);
|
||||
},
|
||||
|
||||
destroy() {
|
||||
Services.obs.removeObserver(this, "http-on-opening-request");
|
||||
ChannelEventSinkFactory.getService().unregisterCollector(this);
|
||||
},
|
||||
|
||||
_saveStackTrace(channel, stacktrace) {
|
||||
this.stacktracesById.set(channel.channelId, stacktrace);
|
||||
},
|
||||
|
||||
observe(subject) {
|
||||
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
||||
if (!matchRequest(channel, this.filters)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the nsIStackFrame XPCOM objects to a nice JSON that can be
|
||||
// passed around through message managers etc.
|
||||
let frame = components.stack;
|
||||
let stacktrace = [];
|
||||
if (frame && frame.caller) {
|
||||
frame = frame.caller;
|
||||
while (frame) {
|
||||
stacktrace.push({
|
||||
filename: frame.filename,
|
||||
lineNumber: frame.lineNumber,
|
||||
columnNumber: frame.columnNumber,
|
||||
functionName: frame.name
|
||||
});
|
||||
if (frame.asyncCaller) {
|
||||
frame = frame.asyncCaller;
|
||||
} else {
|
||||
frame = frame.caller;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._saveStackTrace(channel, stacktrace);
|
||||
},
|
||||
|
||||
onChannelRedirect(oldChannel, newChannel, flags) {
|
||||
// We can be called with any nsIChannel, but are interested only in HTTP channels
|
||||
try {
|
||||
oldChannel.QueryInterface(Ci.nsIHttpChannel);
|
||||
newChannel.QueryInterface(Ci.nsIHttpChannel);
|
||||
} catch (ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
let oldId = oldChannel.channelId;
|
||||
let stacktrace = this.stacktracesById.get(oldId);
|
||||
if (stacktrace) {
|
||||
this.stacktracesById.delete(oldId);
|
||||
this._saveStackTrace(newChannel, stacktrace);
|
||||
}
|
||||
},
|
||||
|
||||
getStackTrace(channelId) {
|
||||
let trace = this.stacktracesById.get(channelId);
|
||||
this.stacktracesById.delete(channelId);
|
||||
return trace;
|
||||
}
|
||||
};
|
||||
|
||||
exports.StackTraceCollector = StackTraceCollector;
|
||||
|
||||
/**
|
||||
* The network response listener implements the nsIStreamListener and
|
||||
* nsIRequestObserver interfaces. This is used within the NetworkMonitor feature
|
||||
|
@ -293,6 +63,7 @@ function NetworkResponseListener(owner, httpActivity) {
|
|||
this._wrappedNotificationCallbacks = channel.notificationCallbacks;
|
||||
channel.notificationCallbacks = this;
|
||||
}
|
||||
exports.NetworkResponseListener = NetworkResponseListener;
|
||||
|
||||
NetworkResponseListener.prototype = {
|
||||
QueryInterface:
|
||||
|
@ -691,7 +462,7 @@ NetworkResponseListener.prototype = {
|
|||
* @param object filters
|
||||
* Object with the filters to use for network requests:
|
||||
* - window (nsIDOMWindow): filter network requests by the associated
|
||||
* window object.
|
||||
* window object.
|
||||
* - appId (number): filter requests by the appId.
|
||||
* - topFrame (nsIDOMElement): filter requests by their topFrameElement.
|
||||
* Filters are optional. If any of these filters match the request is
|
||||
|
@ -700,17 +471,23 @@ NetworkResponseListener.prototype = {
|
|||
* @param object owner
|
||||
* The network monitor owner. This object needs to hold:
|
||||
* - onNetworkEvent(requestInfo, channel, networkMonitor).
|
||||
* This method is invoked once for every new network request and it is
|
||||
* given the following arguments: the initial network request
|
||||
* information, and the channel. The third argument is the NetworkMonitor
|
||||
* instance. onNetworkEvent() must return an object which holds several add*()
|
||||
* methods which are used to add further network request/response
|
||||
* information.
|
||||
* - stackTraceCollector If the owner has this optional property, it will
|
||||
* be used as a StackTraceCollector by the NetworkMonitor.
|
||||
* This method is invoked once for every new network request and it is
|
||||
* given the following arguments: the initial network request
|
||||
* information, and the channel. The third argument is the NetworkMonitor
|
||||
* instance.
|
||||
* onNetworkEvent() must return an object which holds several add*()
|
||||
* methods which are used to add further network request/response
|
||||
* information.
|
||||
*/
|
||||
function NetworkMonitor(filters, owner) {
|
||||
this.filters = filters;
|
||||
if (filters) {
|
||||
this.window = filters.window;
|
||||
this.appId = filters.appId;
|
||||
this.topFrame = filters.topFrame;
|
||||
}
|
||||
if (!this.window && !this.appId && !this.topFrame) {
|
||||
this._logEverything = true;
|
||||
}
|
||||
this.owner = owner;
|
||||
this.openRequests = {};
|
||||
this.openResponses = {};
|
||||
|
@ -718,11 +495,13 @@ function NetworkMonitor(filters, owner) {
|
|||
DevToolsUtils.makeInfallible(this._httpResponseExaminer).bind(this);
|
||||
this._serviceWorkerRequest = this._serviceWorkerRequest.bind(this);
|
||||
}
|
||||
|
||||
exports.NetworkMonitor = NetworkMonitor;
|
||||
|
||||
NetworkMonitor.prototype = {
|
||||
filters: null,
|
||||
_logEverything: false,
|
||||
window: null,
|
||||
appId: null,
|
||||
topFrame: null,
|
||||
|
||||
httpTransactionCodes: {
|
||||
0x5001: "REQUEST_HEADER",
|
||||
|
@ -787,7 +566,7 @@ NetworkMonitor.prototype = {
|
|||
_serviceWorkerRequest: function (subject, topic, data) {
|
||||
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
||||
if (!matchRequest(channel, this.filters)) {
|
||||
if (!this._matchRequest(channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -823,7 +602,7 @@ NetworkMonitor.prototype = {
|
|||
|
||||
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
||||
if (!matchRequest(channel, this.filters)) {
|
||||
if (!this._matchRequest(channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -977,6 +756,84 @@ NetworkMonitor.prototype = {
|
|||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Check if a given network request should be logged by this network monitor
|
||||
* instance based on the current filters.
|
||||
*
|
||||
* @private
|
||||
* @param nsIHttpChannel channel
|
||||
* Request to check.
|
||||
* @return boolean
|
||||
* True if the network request should be logged, false otherwise.
|
||||
*/
|
||||
_matchRequest: function (channel) {
|
||||
if (this._logEverything) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ignore requests from chrome or add-on code when we are monitoring
|
||||
// content.
|
||||
// TODO: one particular test (browser_styleeditor_fetch-from-cache.js) needs
|
||||
// the DevToolsUtils.testing check. We will move to a better way to serve
|
||||
// its needs in bug 1167188, where this check should be removed.
|
||||
if (!DevToolsUtils.testing && channel.loadInfo &&
|
||||
channel.loadInfo.loadingDocument === null &&
|
||||
channel.loadInfo.loadingPrincipal ===
|
||||
Services.scriptSecurityManager.getSystemPrincipal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.window) {
|
||||
// Since frames support, this.window may not be the top level content
|
||||
// frame, so that we can't only compare with win.top.
|
||||
let win = NetworkHelper.getWindowForRequest(channel);
|
||||
while (win) {
|
||||
if (win == this.window) {
|
||||
return true;
|
||||
}
|
||||
if (win.parent == win) {
|
||||
break;
|
||||
}
|
||||
win = win.parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.topFrame) {
|
||||
let topFrame = NetworkHelper.getTopFrameForRequest(channel);
|
||||
if (topFrame && topFrame === this.topFrame) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.appId) {
|
||||
let appId = NetworkHelper.getAppIdForRequest(channel);
|
||||
if (appId && appId == this.appId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// The following check is necessary because beacon channels don't come
|
||||
// associated with a load group. Bug 1160837 will hopefully introduce a
|
||||
// platform fix that will render the following code entirely useless.
|
||||
if (channel.loadInfo &&
|
||||
channel.loadInfo.externalContentPolicyType ==
|
||||
Ci.nsIContentPolicy.TYPE_BEACON) {
|
||||
let nonE10sMatch = this.window &&
|
||||
channel.loadInfo.loadingDocument === this.window.document;
|
||||
const loadingPrincipal = channel.loadInfo.loadingPrincipal;
|
||||
let e10sMatch = this.topFrame &&
|
||||
this.topFrame.contentPrincipal &&
|
||||
this.topFrame.contentPrincipal.equals(loadingPrincipal) &&
|
||||
this.topFrame.contentPrincipal.URI.spec == channel.referrer.spec;
|
||||
let b2gMatch = this.appId && loadingPrincipal.appId === this.appId;
|
||||
if (nonE10sMatch || e10sMatch || b2gMatch) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -1000,7 +857,6 @@ NetworkMonitor.prototype = {
|
|||
|
||||
let event = {};
|
||||
event.method = channel.requestMethod;
|
||||
event.channelId = channel.channelId;
|
||||
event.url = channel.URI.spec;
|
||||
event.private = httpActivity.private;
|
||||
event.headersSize = 0;
|
||||
|
@ -1015,26 +871,12 @@ NetworkMonitor.prototype = {
|
|||
event.headersSize = extraStringData.length;
|
||||
}
|
||||
|
||||
// Determine the cause and if this is an XHR request.
|
||||
let causeType = channel.loadInfo.externalContentPolicyType;
|
||||
let loadingPrincipal = channel.loadInfo.loadingPrincipal;
|
||||
let causeUri = loadingPrincipal ? loadingPrincipal.URI : null;
|
||||
let stacktrace;
|
||||
// If this is the parent process, there is no stackTraceCollector - the stack
|
||||
// trace will be added in NetworkMonitorChild._onNewEvent.
|
||||
if (this.owner.stackTraceCollector) {
|
||||
stacktrace = this.owner.stackTraceCollector.getStackTrace(event.channelId);
|
||||
}
|
||||
|
||||
event.cause = {
|
||||
type: causeType,
|
||||
loadingDocumentUri: causeUri ? causeUri.spec : null,
|
||||
stacktrace
|
||||
};
|
||||
|
||||
// Determine if this is an XHR request.
|
||||
httpActivity.isXHR = event.isXHR =
|
||||
(causeType === Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST ||
|
||||
causeType === Ci.nsIContentPolicy.TYPE_FETCH);
|
||||
(channel.loadInfo.externalContentPolicyType ===
|
||||
Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST ||
|
||||
channel.loadInfo.externalContentPolicyType ===
|
||||
Ci.nsIContentPolicy.TYPE_FETCH);
|
||||
|
||||
// Determine the HTTP version.
|
||||
let httpVersionMaj = {};
|
||||
|
@ -1090,11 +932,12 @@ NetworkMonitor.prototype = {
|
|||
* @return void
|
||||
*/
|
||||
_onRequestHeader: function (channel, timestamp, extraStringData) {
|
||||
if (!matchRequest(channel, this.filters)) {
|
||||
if (!this._matchRequest(channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._createNetworkEvent(channel, { timestamp, extraStringData });
|
||||
this._createNetworkEvent(channel, { timestamp: timestamp,
|
||||
extraStringData: extraStringData });
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1384,7 +1227,8 @@ NetworkMonitor.prototype = {
|
|||
this.openRequests = {};
|
||||
this.openResponses = {};
|
||||
this.owner = null;
|
||||
this.filters = null;
|
||||
this.window = null;
|
||||
this.topFrame = null;
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1420,7 +1264,6 @@ function NetworkMonitorChild(appId, messageManager, connID, owner) {
|
|||
this._onUpdateEvent = this._onUpdateEvent.bind(this);
|
||||
this._netEvents = new Map();
|
||||
}
|
||||
|
||||
exports.NetworkMonitorChild = NetworkMonitorChild;
|
||||
|
||||
NetworkMonitorChild.prototype = {
|
||||
|
@ -1437,6 +1280,7 @@ NetworkMonitorChild.prototype = {
|
|||
this._saveRequestAndResponseBodies = val;
|
||||
|
||||
this._messageManager.sendAsyncMessage("debug:netmonitor:" + this.connID, {
|
||||
appId: this.appId,
|
||||
action: "setPreferences",
|
||||
preferences: {
|
||||
saveRequestAndResponseBodies: this._saveRequestAndResponseBodies,
|
||||
|
@ -1458,13 +1302,6 @@ NetworkMonitorChild.prototype = {
|
|||
|
||||
_onNewEvent: DevToolsUtils.makeInfallible(function _onNewEvent(msg) {
|
||||
let {id, event} = msg.data;
|
||||
|
||||
// Try to add stack trace to the event data received from parent
|
||||
if (this.owner.stackTraceCollector) {
|
||||
event.cause.stacktrace =
|
||||
this.owner.stackTraceCollector.getStackTrace(event.channelId);
|
||||
}
|
||||
|
||||
let actor = this.owner.onNetworkEvent(event);
|
||||
this._netEvents.set(id, Cu.getWeakReference(actor));
|
||||
}),
|
||||
|
@ -1611,12 +1448,11 @@ NetworkMonitorManager.prototype = {
|
|||
* Message from the content.
|
||||
*/
|
||||
onNetMonitorMessage: DevToolsUtils.makeInfallible(function (msg) {
|
||||
let {action} = msg.json;
|
||||
let { action, appId } = msg.json;
|
||||
// Pipe network monitor data from parent to child via the message manager.
|
||||
switch (action) {
|
||||
case "start":
|
||||
if (!this.netMonitor) {
|
||||
let {appId} = msg.json;
|
||||
this.netMonitor = new NetworkMonitor({
|
||||
topFrame: this.frame,
|
||||
appId: appId,
|
||||
|
|
Загрузка…
Ссылка в новой задаче