Bug 731318 - Show transferred size in Net Monitor. r=vporof

This commit is contained in:
J. Ryan Stinnett 2014-12-22 12:15:48 -06:00
parent 440967c333
commit c0cf86a5c7
14 changed files with 183 additions and 9 deletions

View File

@ -391,6 +391,16 @@ let NetMonitorController = {
!this._target.isApp);
},
/**
* Getter that tells if the server includes the transferred (compressed /
* encoded) response size.
* @type boolean
*/
get supportsTransferredResponseSize() {
return this.webConsoleClient &&
this.webConsoleClient.traits.transferredResponseSize;
},
/**
* Getter that tells if the server can do network performance statistics.
* @type boolean
@ -590,6 +600,7 @@ NetworkEventsHandler.prototype = {
case "responseContent":
NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
contentSize: aPacket.contentSize,
transferredSize: aPacket.transferredSize,
mimeType: aPacket.mimeType
});
this.webConsoleClient.getResponseContent(actor, this._onResponseContent);

View File

@ -416,6 +416,11 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
$("#requests-menu-network-summary-button").hidden = true;
$("#requests-menu-network-summary-label").hidden = true;
}
if (!NetMonitorController.supportsTransferredResponseSize) {
$("#requests-menu-transferred-header-box").hidden = true;
$("#requests-menu-item-template .requests-menu-transferred").hidden = true;
}
},
/**
@ -799,8 +804,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
* Sorts all network requests in this container by a specified detail.
*
* @param string aType
* Either "status", "method", "file", "domain", "type", "size" or
* "waterfall".
* Either "status", "method", "file", "domain", "type", "transferred",
* "size" or "waterfall".
*/
sortBy: function(aType = "waterfall") {
let target = $("#requests-menu-" + aType + "-button");
@ -861,6 +866,13 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
this.sortContents((a, b) => !this._byType(a, b));
}
break;
case "transferred":
if (direction == "ascending") {
this.sortContents(this._byTransferred);
} else {
this.sortContents((a, b) => !this._byTransferred(a, b));
}
break;
case "size":
if (direction == "ascending") {
this.sortContents(this._bySize);
@ -993,8 +1005,13 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
: firstType > secondType;
},
_bySize: function({ attachment: first }, { attachment: second })
first.contentSize > second.contentSize,
_byTransferred: function({ attachment: first }, { attachment: second }) {
return first.transferredSize > second.transferredSize;
},
_bySize: function({ attachment: first }, { attachment: second }) {
return first.contentSize > second.contentSize;
},
/**
* Refreshes the status displayed in this container's footer, providing
@ -1159,6 +1176,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
requestItem.attachment.contentSize = value;
this.updateMenuView(requestItem, key, value);
break;
case "transferredSize":
requestItem.attachment.transferredSize = value;
this.updateMenuView(requestItem, key, value);
break;
case "mimeType":
requestItem.attachment.mimeType = value;
this.updateMenuView(requestItem, key, value);
@ -1307,6 +1328,20 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
node.setAttribute("tooltiptext", text);
break;
}
case "transferredSize": {
let text;
if (aValue === null) {
text = L10N.getStr("networkMenu.sizeUnavailable");
} else {
let kb = aValue / 1024;
let size = L10N.numberWithDecimals(kb, CONTENT_SIZE_DECIMALS);
text = L10N.getFormatStr("networkMenu.sizeKB", size);
}
let node = $(".requests-menu-transferred", target);
node.setAttribute("value", text);
node.setAttribute("tooltiptext", text);
break;
}
case "mimeType": {
let type = this._getAbbreviatedMimeType(aValue);
let node = $(".requests-menu-type", target);

View File

@ -101,6 +101,16 @@
flex="1">
</button>
</hbox>
<hbox id="requests-menu-transferred-header-box"
class="requests-menu-header requests-menu-transferred"
align="center">
<button id="requests-menu-transferred-button"
class="requests-menu-header-button requests-menu-transferred"
data-key="transferred"
label="&netmonitorUI.toolbar.transferred;"
flex="1">
</button>
</hbox>
<hbox id="requests-menu-size-header-box"
class="requests-menu-header requests-menu-size"
align="center">
@ -174,6 +184,8 @@
crop="end"/>
<label class="plain requests-menu-subitem requests-menu-type"
crop="end"/>
<label class="plain requests-menu-subitem requests-menu-transferred"
crop="end"/>
<label class="plain requests-menu-subitem requests-menu-size"
crop="end"/>
<hbox class="requests-menu-subitem requests-menu-waterfall"

View File

@ -65,6 +65,8 @@ function test() {
is(requestItem.attachment.headersSize, undefined,
"The headersSize should not yet be set.");
is(requestItem.attachment.transferredSize, undefined,
"The transferredSize should not yet be set.");
is(requestItem.attachment.contentSize, undefined,
"The contentSize should not yet be set.");
@ -156,6 +158,8 @@ function test() {
aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.UPDATING_RESPONSE_CONTENT, () => {
let requestItem = RequestsMenu.getItemAtIndex(0);
is(requestItem.attachment.transferredSize, "12",
"The transferredSize attachment has an incorrect value.");
is(requestItem.attachment.contentSize, "12",
"The contentSize attachment has an incorrect value.");
is(requestItem.attachment.mimeType, "text/plain; charset=utf-8",
@ -164,6 +168,7 @@ function test() {
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
type: "plain",
fullMimeType: "text/plain; charset=utf-8",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
});
});
@ -183,6 +188,7 @@ function test() {
verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
type: "plain",
fullMimeType: "text/plain; charset=utf-8",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
});
});

View File

@ -202,6 +202,7 @@ function test() {
statusText: "Switching Protocols",
type: "plain",
fullMimeType: "text/plain; charset=utf-8",
transferred: L10N.getStr("networkMenu.sizeUnavailable"),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
time: true
});
@ -211,6 +212,7 @@ function test() {
statusText: "Created",
type: "plain",
fullMimeType: "text/plain; charset=utf-8",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
time: true
});
@ -220,6 +222,7 @@ function test() {
statusText: "See Other",
type: "plain",
fullMimeType: "text/plain; charset=utf-8",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
time: true
});
@ -229,6 +232,7 @@ function test() {
statusText: "Not Found",
type: "plain",
fullMimeType: "text/plain; charset=utf-8",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
time: true
});
@ -238,6 +242,7 @@ function test() {
statusText: "Not Implemented",
type: "plain",
fullMimeType: "text/plain; charset=utf-8",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
time: true
});

View File

@ -102,6 +102,24 @@ function test() {
testHeaders("type", "ascending");
return testContents([0, 1, 2, 3, 4]);
})
.then(() => {
info("Testing transferred sort, ascending.");
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-transferred-button"));
testHeaders("transferred", "ascending");
return testContents([0, 1, 2, 3, 4]);
})
.then(() => {
info("Testing transferred sort, descending.");
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-transferred-button"));
testHeaders("transferred", "descending");
return testContents([4, 3, 2, 1, 0]);
})
.then(() => {
info("Testing transferred sort, ascending. Checking sort loops correctly.");
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-transferred-button"));
testHeaders("transferred", "ascending");
return testContents([0, 1, 2, 3, 4]);
})
.then(() => {
info("Testing size sort, ascending.");
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
@ -199,6 +217,7 @@ function test() {
statusText: "Meh",
type: "1",
fullMimeType: "text/1",
transferred: L10N.getStr("networkMenu.sizeUnavailable"),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
time: true
});
@ -209,6 +228,7 @@ function test() {
statusText: "Meh",
type: "2",
fullMimeType: "text/2",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
time: true
});
@ -219,6 +239,7 @@ function test() {
statusText: "Meh",
type: "3",
fullMimeType: "text/3",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
time: true
});
@ -229,6 +250,7 @@ function test() {
statusText: "Meh",
type: "4",
fullMimeType: "text/4",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
time: true
});
@ -239,6 +261,7 @@ function test() {
statusText: "Meh",
type: "5",
fullMimeType: "text/5",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
time: true
});

View File

@ -130,6 +130,7 @@ function test() {
statusText: "Meh",
type: "1",
fullMimeType: "text/1",
transferred: L10N.getStr("networkMenu.sizeUnavailable"),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
time: true
});
@ -142,6 +143,7 @@ function test() {
statusText: "Meh",
type: "2",
fullMimeType: "text/2",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
time: true
});
@ -154,6 +156,7 @@ function test() {
statusText: "Meh",
type: "3",
fullMimeType: "text/3",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
time: true
});
@ -166,6 +169,7 @@ function test() {
statusText: "Meh",
type: "4",
fullMimeType: "text/4",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
time: true
});
@ -178,6 +182,7 @@ function test() {
statusText: "Meh",
type: "5",
fullMimeType: "text/5",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
time: true
});

View File

@ -12,6 +12,12 @@ function test() {
let { document, L10N, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
// Disable transferred size column support for this test.
// Without this, the waterfall only has enough room for one division, which
// would remove most of the value of this test.
document.querySelector("#requests-menu-transferred-header-box").hidden = true;
document.querySelector("#requests-menu-item-template .requests-menu-transferred").hidden = true;
RequestsMenu.lazyUpdate = false;
ok(document.querySelector("#requests-menu-waterfall-label"),

View File

@ -264,7 +264,7 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
info("Widget index of item: " + widgetIndex);
info("Visible index of item: " + visibleIndex);
let { fuzzyUrl, status, statusText, type, fullMimeType, size, time } = aData;
let { fuzzyUrl, status, statusText, type, fullMimeType, transferred, size, time } = aData;
let { attachment, target } = aRequestItem
let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
@ -319,6 +319,14 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
is(value, type, "The displayed type is incorrect.");
is(tooltip, fullMimeType, "The tooltip type is incorrect.");
}
if (transferred !== undefined) {
let value = target.querySelector(".requests-menu-transferred").getAttribute("value");
let tooltip = target.querySelector(".requests-menu-transferred").getAttribute("tooltiptext");
info("Displayed transferred size: " + value);
info("Tooltip transferred size: " + tooltip);
is(value, transferred, "The displayed transferred size is incorrect.");
is(tooltip, transferred, "The tooltip transferred size is incorrect.");
}
if (size !== undefined) {
let value = target.querySelector(".requests-menu-size").getAttribute("value");
let tooltip = target.querySelector(".requests-menu-size").getAttribute("tooltiptext");

View File

@ -42,8 +42,14 @@
- in the network table toolbar, above the "type" column. -->
<!ENTITY netmonitorUI.toolbar.type "Type">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.transferred): This is the label displayed
- in the network table toolbar, above the "transferred" column, which is the
- compressed / encoded size. -->
<!ENTITY netmonitorUI.toolbar.transferred "Transferred">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.size): This is the label displayed
- in the network table toolbar, above the "size" column. -->
- in the network table toolbar, above the "size" column, which is the
- uncompressed / decoded size. -->
<!ENTITY netmonitorUI.toolbar.size "Size">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.waterfall): This is the label displayed

View File

@ -129,6 +129,11 @@ networkMenu.summary=One request, #2 KB, #3 s;#1 requests, #2 KB, #3 s
# in the network menu specifying the size of a request (in kilobytes).
networkMenu.sizeKB=%S KB
# LOCALIZATION NOTE (networkMenu.sizeUnavailable): This is the label displayed
# in the network menu specifying the transferred size of a request is
# unavailable.
networkMenu.sizeUnavailable=
# 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

View File

@ -166,6 +166,11 @@
width: 8em;
}
.requests-menu-transferred {
text-align: center;
width: 8em;
}
/* Network requests table: status codes */
box.requests-menu-status {

View File

@ -83,6 +83,7 @@ function WebConsoleActor(aConnection, aParentActor)
this.traits = {
customNetworkRequest: !this._parentIsContentActor,
transferredResponseSize: true
};
}
@ -1974,6 +1975,7 @@ NetworkEventActor.prototype =
updateType: "responseContent",
mimeType: aContent.mimeType,
contentSize: aContent.text.length,
transferredSize: aContent.transferredSize,
discardResponseBody: aDiscardedResponseBody,
};

View File

@ -4,7 +4,7 @@
"use strict";
const {Cc, Ci, Cu} = require("chrome");
const {Cc, Ci, Cu, Cr} = require("chrome");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -57,13 +57,33 @@ function NetworkResponseListener(aOwner, aHttpActivity)
this.receivedData = "";
this.httpActivity = aHttpActivity;
this.bodySize = 0;
let channel = this.httpActivity.channel;
this._wrappedNotificationCallbacks = channel.notificationCallbacks;
channel.notificationCallbacks = this;
}
exports.NetworkResponseListener = NetworkResponseListener;
NetworkResponseListener.prototype = {
QueryInterface:
XPCOMUtils.generateQI([Ci.nsIStreamListener, Ci.nsIInputStreamCallback,
Ci.nsIRequestObserver, Ci.nsISupports]),
Ci.nsIRequestObserver, Ci.nsIInterfaceRequestor,
Ci.nsISupports]),
// nsIInterfaceRequestor implementation
/**
* This object implements nsIProgressEventSink, but also needs to forward
* interface requests to the notification callbacks of other objects.
*/
getInterface(iid) {
if (iid.equals(Ci.nsIProgressEventSink)) {
return this;
}
if (this._wrappedNotificationCallbacks) {
return this._wrappedNotificationCallbacks.getInterface(iid);
}
throw Cr.NS_ERROR_NO_INTERFACE;
},
/**
* This NetworkResponseListener tracks the NetworkMonitor.openResponses object
@ -72,6 +92,12 @@ NetworkResponseListener.prototype = {
*/
_foundOpenResponse: false,
/**
* If the channel already had notificationCallbacks, hold them here internally
* so that we can forward getInterface requests to that object.
*/
_wrappedNotificationCallbacks: null,
/**
* The response listener owner.
*/
@ -94,10 +120,15 @@ NetworkResponseListener.prototype = {
receivedData: null,
/**
* The network response body size.
* The uncompressed, decoded response body size.
*/
bodySize: null,
/**
* Response body size on the wire, potentially compressed / encoded.
*/
transferredSize: null,
/**
* The nsIRequest we are started for.
*/
@ -177,6 +208,18 @@ NetworkResponseListener.prototype = {
this.sink.outputStream.close();
},
// nsIProgressEventSink implementation
/**
* Handle progress event as data is transferred. This is used to record the
* size on the wire, which may be compressed / encoded.
*/
onProgress: function(request, context, progress, progressMax) {
this.transferredSize = progress;
},
onStatus: function () {},
/**
* Find the open response object associated to the current request. The
* NetworkMonitor._httpResponseExaminer() method saves the response headers in
@ -259,6 +302,7 @@ NetworkResponseListener.prototype = {
};
response.size = response.text.length;
response.transferredSize = this.transferredSize;
try {
response.mimeType = this.request.contentType;
@ -279,6 +323,7 @@ NetworkResponseListener.prototype = {
this.httpActivity.owner.
addResponseContent(response, this.httpActivity.discardResponseBody);
this._wrappedNotificationCallbacks = null;
this.httpActivity.channel = null;
this.httpActivity.owner = null;
this.httpActivity = null;