mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Backed out 3 changesets (bug 1134073) because maybe it broke the clipboard tests
Backed out changeset a43d99734390 (bug 1134073) Backed out changeset 572ebec612e8 (bug 1134073) Backed out changeset f12a69ba9122 (bug 1134073)
This commit is contained in:
parent
b42a94e7c4
commit
ab58bab2bf
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user