bug 1158264 - Flag requests coming from service workers. r=vporof

This commit is contained in:
Alexandre Poirot 2016-01-14 05:53:00 -08:00
Родитель c7c2eba05c
Коммит 335ab17e50
12 изменённых файлов: 233 добавлений и 22 удалений

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

@ -74,6 +74,16 @@ netmonitor.security.hostHeader=Host %S:
# Organization: <Not Available>
netmonitor.security.notAvailable=<Not Available>
# LOCALIZATION NOTE (netmonitor.status.cached):
# This string is used as tooltip text over the status icon when a request is
# served from cached.
netmonitor.status.cached=cached
# LOCALIZATION NOTE (netmonitor.status.serviceWorker):
# This string is used as tooltip text over the status icon when a request is
# served from a service worker.
netmonitor.status.serviceWorker=service worker
# LOCALIZATION NOTE (collapseDetailsPane): This is the tooltip for the button
# that collapses the network details pane in the UI.
collapseDetailsPane=Hide request details
@ -184,6 +194,11 @@ networkMenu.sizeUnavailable=—
# cached.
networkMenu.sizeCached=cached
# LOCALIZATION NOTE (networkMenu.sizeServiceWorker): This is the label displayed
# in the network menu specifying the transferred of a request computed
# by a service worker.
networkMenu.sizeServiceWorker=service worker
# LOCALIZATION NOTE (networkMenu.totalMS): This is the label displayed
# in the network menu specifying the time for a request to finish (in milliseconds).
networkMenu.totalMS=→ %S ms

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

@ -606,10 +606,10 @@ NetworkEventsHandler.prototype = {
* The network request information.
*/
_onNetworkEvent: function(type, networkInfo) {
let { actor, startedDateTime, request: { method, url }, isXHR, fromCache } = networkInfo;
let { actor, startedDateTime, request: { method, url }, isXHR, fromCache, fromServiceWorker } = networkInfo;
NetMonitorView.RequestsMenu.addRequest(
actor, startedDateTime, method, url, isXHR, fromCache
actor, startedDateTime, method, url, isXHR, fromCache, fromServiceWorker
);
window.emit(EVENTS.NETWORK_EVENT, actor);
},

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

@ -538,9 +538,11 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
* True if this request was initiated via XHR.
* @param boolean aFromCache
* Indicates if the result came from the browser cache
* @param boolean aFromServiceWorker
* Indicates if the request has been intercepted by a Service Worker
*/
addRequest: function(aId, aStartedDateTime, aMethod, aUrl, aIsXHR, aFromCache) {
this._addQueue.push([aId, aStartedDateTime, aMethod, aUrl, aIsXHR, aFromCache]);
addRequest: function(aId, aStartedDateTime, aMethod, aUrl, aIsXHR, aFromCache, aFromServiceWorker) {
this._addQueue.push([aId, aStartedDateTime, aMethod, aUrl, aIsXHR, aFromCache, aFromServiceWorker]);
// Lazy updating is disabled in some tests.
if (!this.lazyUpdate) {
@ -1349,7 +1351,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
let widget = NetMonitorView.RequestsMenu.widget;
let isScrolledToBottom = widget.isScrolledToBottom();
for (let [id, startedDateTime, method, url, isXHR, fromCache] of this._addQueue) {
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);
@ -1368,7 +1370,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
method: method,
url: url,
isXHR: isXHR,
fromCache: fromCache
fromCache: fromCache,
fromServiceWorker: fromServiceWorker
}
});
@ -1470,7 +1473,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
requestItem.attachment.status = value;
this.updateMenuView(requestItem, key, {
status: value,
cached: requestItem.attachment.fromCache
cached: requestItem.attachment.fromCache,
serviceWorker: requestItem.attachment.fromServiceWorker
});
break;
case "statusText":
@ -1479,6 +1483,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
requestItem.attachment.statusText);
if(requestItem.attachment.fromCache) {
text += " (cached)";
} else if(requestItem.attachment.fromServiceWorker) {
text += " (service worker)";
}
this.updateMenuView(requestItem, key, text);
@ -1495,6 +1501,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
requestItem.attachment.transferredSize = 0;
this.updateMenuView(requestItem, key, 'cached');
}
else if(requestItem.attachment.fromServiceWorker) {
requestItem.attachment.transferredSize = 0;
this.updateMenuView(requestItem, key, 'service worker');
}
else {
requestItem.attachment.transferredSize = value;
this.updateMenuView(requestItem, key, value);
@ -1523,7 +1533,9 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
case "eventTimings":
requestItem.attachment.eventTimings = value;
this._createWaterfallView(
requestItem, value.timings, requestItem.attachment.fromCache
requestItem, value.timings,
requestItem.attachment.fromCache ||
requestItem.attachment.fromServiceWorker
);
break;
}
@ -1682,7 +1694,16 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
}
case "status": {
let node = $(".requests-menu-status-icon", target);
node.setAttribute("code", aValue.cached ? "cached" : aValue.status);
let code;
if (aValue.cached) {
code = L10N.getStr("netmonitor.status.cached");
code = "cached";
} else if (aValue.serviceWorker) {
code = L10N.getStr("netmonitor.status.serviceWorker");
} else {
code = aValue.status;
}
node.setAttribute("code", code);
let codeNode = $(".requests-menu-status-code", target);
codeNode.setAttribute("value", aValue.status);
break;
@ -1712,6 +1733,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
text = L10N.getStr("networkMenu.sizeCached");
node.classList.add('theme-comment');
}
else if(aValue === "service worker") {
text = L10N.getStr("networkMenu.sizeServiceWorker");
node.classList.add('theme-comment');
}
else {
let kb = aValue / 1024;
let size = L10N.numberWithDecimals(kb, CONTENT_SIZE_DECIMALS);
@ -1763,7 +1788,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
* @param object aTimings
* An object containing timing information.
* @param boolean aFromCache
* Indicates if the result came from the browser cache
* Indicates if the result came from the browser cache or a service worker
*/
_createWaterfallView: function(aItem, aTimings, aFromCache) {
let { target, attachment } = aItem;
@ -2690,7 +2715,15 @@ NetworkDetailsView.prototype = {
}
if (aData.status) {
$("#headers-summary-status-circle").setAttribute("code", aData.fromCache ? "cached" : aData.status);
let code;
if (aData.fromCache) {
code = L10N.getStr("netmonitor.status.cached");
} else if (aData.fromServiceWorker) {
code = L10N.getStr("netmonitor.status.serviceWorker");
} else {
code = aData.status;
}
$("#headers-summary-status-circle").setAttribute("code", code);
$("#headers-summary-status-value").setAttribute("value", aData.status + " " + aData.statusText);
$("#headers-summary-status").removeAttribute("hidden");
} else {

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

@ -36,6 +36,8 @@ support-files =
sjs_sorting-test-server.sjs
sjs_status-codes-test-server.sjs
test-image.png
service-workers/status-codes.html
service-workers/status-codes-service-worker.js
[browser_net_aaa_leaktest.js]
[browser_net_accessibility-01.js]
@ -43,6 +45,7 @@ support-files =
[browser_net_api-calls.js]
[browser_net_autoscroll.js]
[browser_net_cached-status.js]
[browser_net_service-worker-status.js]
[browser_net_charts-01.js]
[browser_net_charts-02.js]
[browser_net_charts-03.js]

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

@ -61,7 +61,7 @@ var test = Task.async(function*() {
details: {
status: 200,
statusText: "OK (cached)",
fromCache: true,
displayedStatus : "cached",
type: "plain",
fullMimeType: "text/plain; charset=utf-8"
}
@ -72,7 +72,7 @@ var test = Task.async(function*() {
details: {
status: 301,
statusText: "Moved Permanently (cached)",
fromCache: true,
displayedStatus: "cached",
type: "html",
fullMimeType: "text/html; charset=utf-8"
}

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

@ -0,0 +1,55 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests if requests intercepted by service workers have the correct status code
*/
// Service workers only work on https
const URL = EXAMPLE_URL.replace("http:", "https:");
const TEST_URL = URL + "service-workers/status-codes.html";
var test = Task.async(function*() {
let [tab, debuggee, monitor] = yield initNetMonitor(TEST_URL, null, true);
info("Starting test... ");
let { document, L10N, NetMonitorView } = monitor.panelWin;
let { RequestsMenu, NetworkDetails } = NetMonitorView;
const REQUEST_DATA = [
{
method: 'GET',
uri: URL + "service-workers/test/200",
details: {
status: 200,
statusText: 'OK (service worker)',
displayedStatus: 'service worker',
type: "plain",
fullMimeType: "text/plain; charset=UTF-8"
}
},
];
info("Registering the service worker...");
yield debuggee.registerServiceWorker();
info("Performing requests...");
debuggee.performRequests();
yield waitForNetworkEvents(monitor, REQUEST_DATA.length);
let index = 0;
for (let request of REQUEST_DATA) {
let item = RequestsMenu.getItemAtIndex(index);
info("Verifying request #" + index);
yield verifyRequestItemTarget(item, request.method, request.uri, request.details);
index++;
}
yield teardown(monitor);
finish();
});

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

@ -283,7 +283,7 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
info("Visible index of item: " + visibleIndex);
let { fuzzyUrl, status, statusText, type, fullMimeType,
transferred, size, time, fromCache } = aData;
transferred, size, time, displayedStatus } = aData;
let { attachment, target } = aRequestItem
let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
@ -330,7 +330,7 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
info("Displayed status: " + value);
info("Displayed code: " + codeValue);
info("Tooltip status: " + tooltip);
is(value, fromCache ? "cached" : status, "The displayed status is correct.");
is(value, displayedStatus ? displayedStatus : status, "The displayed status is correct.");
is(codeValue, status, "The displayed status code is correct.");
is(tooltip, status + " " + statusText, "The tooltip status is correct.");
}

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

@ -0,0 +1,8 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
addEventListener("fetch", function(event) {
let response = new Response("Service worker response");
event.respondWith(response);
});

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

@ -0,0 +1,39 @@
<!-- 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>
</head>
<body>
<p>Status codes test</p>
<script type="text/javascript">
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 registerServiceWorker() {
return navigator.serviceWorker.register("status-codes-service-worker.js")
.then(() => navigator.serviceWorker.ready);
}
function performRequests() {
return get("test/200");
}
</script>
</body>
</html>

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

@ -283,6 +283,11 @@ WebConsoleActor.prototype =
*/
networkMonitor: null,
/**
* The NetworkMonitor instance living in the same (child) process.
*/
networkMonitorChild: null,
/**
* The ConsoleProgressListener instance.
*/
@ -343,6 +348,10 @@ WebConsoleActor.prototype =
this.networkMonitor.destroy();
this.networkMonitor = null;
}
if (this.networkMonitorChild) {
this.networkMonitorChild.destroy();
this.networkMonitorChild = null;
}
if (this.consoleProgressListener) {
this.consoleProgressListener.destroy();
this.consoleProgressListener = null;
@ -587,14 +596,21 @@ WebConsoleActor.prototype =
case "NetworkActivity":
if (!this.networkMonitor) {
if (appId || messageManager) {
// Start a network monitor in the parent process to listen to
// most requests than happen in parent
this.networkMonitor =
new NetworkMonitorChild(appId, messageManager,
this.parentActor.actorID, this);
this.networkMonitor.init();
// Spawn also one in the child to listen to service workers
this.networkMonitorChild = new NetworkMonitor({ window: window },
this);
this.networkMonitorChild.init();
}
else {
this.networkMonitor = new NetworkMonitor({ window: window }, this);
this.networkMonitor.init();
}
this.networkMonitor.init();
}
startedListeners.push(listener);
break;
@ -677,6 +693,10 @@ WebConsoleActor.prototype =
this.networkMonitor.destroy();
this.networkMonitor = null;
}
if (this.networkMonitorChild) {
this.networkMonitorChild.destroy();
this.networkMonitorChild = null;
}
stoppedListeners.push(listener);
break;
case "FileActivity":
@ -1734,6 +1754,7 @@ NetworkEventActor.prototype =
method: this._request.method,
isXHR: this._isXHR,
fromCache: this._fromCache,
fromServiceWorker: this._fromServiceWorker,
private: this._private,
};
},
@ -1778,6 +1799,7 @@ NetworkEventActor.prototype =
this._startedDateTime = aNetworkEvent.startedDateTime;
this._isXHR = aNetworkEvent.isXHR;
this._fromCache = aNetworkEvent.fromCache;
this._fromServiceWorker = aNetworkEvent.fromServiceWorker;
for (let prop of ['method', 'url', 'httpVersion', 'headersSize']) {
this._request[prop] = aNetworkEvent[prop];

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

@ -105,7 +105,8 @@ WebConsoleClient.prototype = {
timings: {},
updates: [], // track the list of network event updates
private: actor.private,
fromCache: actor.fromCache
fromCache: actor.fromCache,
fromServiceWorker: actor.fromServiceWorker
};
this._networkRequests.set(actor.actor, networkInfo);

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

@ -491,6 +491,7 @@ function NetworkMonitor(aFilters, aOwner)
this.openResponses = {};
this._httpResponseExaminer =
DevToolsUtils.makeInfallible(this._httpResponseExaminer).bind(this);
this._serviceWorkerRequest = this._serviceWorkerRequest.bind(this);
}
exports.NetworkMonitor = NetworkMonitor;
@ -546,15 +547,35 @@ NetworkMonitor.prototype = {
{
this.responsePipeSegmentSize = Services.prefs
.getIntPref("network.buffer.cache.size");
gActivityDistributor.addObserver(this);
this.interceptedChannels = new Set();
if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT) {
gActivityDistributor.addObserver(this);
Services.obs.addObserver(this._httpResponseExaminer,
"http-on-examine-response", false);
Services.obs.addObserver(this._httpResponseExaminer,
"http-on-examine-cached-response", false);
}
// In child processes, only watch for service worker requests
// everything else only happens in the parent process
Services.obs.addObserver(this._serviceWorkerRequest,
"service-worker-synthesized-response", false);
},
_serviceWorkerRequest: function(aSubject, aTopic, aData)
{
let channel = aSubject.QueryInterface(Ci.nsIHttpChannel);
if (!this._matchRequest(channel)) {
return;
}
this.interceptedChannels.add(aSubject);
// On e10s, we never receive http-on-examine-cached-response, so fake one.
if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT) {
this._httpResponseExaminer(channel, "http-on-examine-cached-response");
}
},
/**
@ -628,10 +649,18 @@ NetworkMonitor.prototype = {
this.openResponses[response.id] = response;
if (aTopic === "http-on-examine-cached-response") {
// Service worker requests emits cached-reponse notification on non-e10s,
// and we fake one on e10s.
let fromServiceWorker = this.interceptedChannels.has(channel);
this.interceptedChannels.delete(channel);
// If this is a cached response, there never was a request event
// so we need to construct one here so the frontend gets all the
// expected events.
let httpActivity = this._createNetworkEvent(channel, { fromCache: true });
let httpActivity = this._createNetworkEvent(channel, {
fromCache: !fromServiceWorker,
fromServiceWorker: fromServiceWorker
});
httpActivity.owner.addResponseStart({
httpVersion: response.httpVersion,
remoteAddress: "",
@ -806,7 +835,7 @@ NetworkMonitor.prototype = {
/**
*
*/
_createNetworkEvent: function(aChannel, { timestamp, extraStringData, fromCache }) {
_createNetworkEvent: function(aChannel, { timestamp, extraStringData, fromCache, fromServiceWorker }) {
let win = NetworkHelper.getWindowForRequest(aChannel);
let httpActivity = this.createActivityObject(aChannel);
@ -830,6 +859,7 @@ NetworkMonitor.prototype = {
event.headersSize = 0;
event.startedDateTime = (timestamp ? new Date(Math.round(timestamp / 1000)) : new Date()).toISOString();
event.fromCache = fromCache;
event.fromServiceWorker = fromServiceWorker;
if (extraStringData) {
event.headersSize = extraStringData.length;
@ -1189,12 +1219,17 @@ NetworkMonitor.prototype = {
destroy: function NM_destroy()
{
if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT) {
gActivityDistributor.removeObserver(this);
Services.obs.removeObserver(this._httpResponseExaminer,
"http-on-examine-response");
Services.obs.removeObserver(this._httpResponseExaminer,
"http-on-examine-cached-response");
}
gActivityDistributor.removeObserver(this);
Services.obs.removeObserver(this._serviceWorkerRequest,
"service-worker-synthesized-response");
this.interceptedChannels.clear();
this.openRequests = {};
this.openResponses = {};
this.owner = null;