Bug 982319 - Unzipping response boddies in network monitor when needed. r=ochameau

This commit is contained in:
Gabor Krizsanits 2015-04-29 10:18:27 +02:00
parent 8c28670b1b
commit b1aa4dc962
8 changed files with 120 additions and 10 deletions

View File

@ -14,7 +14,7 @@ function test() {
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 6).then(() => {
waitForNetworkEvents(aMonitor, 7).then(() => {
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
"GET", CONTENT_TYPE_SJS + "?fmt=xml", {
status: 200,
@ -70,6 +70,15 @@ function test() {
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.76),
time: true
});
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(6),
"GET", CONTENT_TYPE_SJS + "?fmt=gzip", {
status: 200,
statusText: "OK",
type: "plain",
fullMimeType: "text/plain",
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 10.73),
time: true
});
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
@ -94,6 +103,9 @@ function test() {
RequestsMenu.selectedIndex = 5;
yield waitForTabUpdated();
yield testResponseTab("png");
RequestsMenu.selectedIndex = 6;
yield waitForTabUpdated();
yield testResponseTab("gzip");
yield teardown(aMonitor);
finish();
});
@ -216,6 +228,19 @@ function test() {
return deferred.promise;
}
case "gzip": {
checkVisibility("textarea");
let expected = new Array(1000).join("Hello gzip!");
return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
is(aEditor.getText(), expected,
"The text shown in the source editor is incorrect for the gzip request.");
is(aEditor.getMode(), Editor.modes.text,
"The mode active in the source editor is incorrect for the gzip request.");
});
}
}
}

View File

@ -14,7 +14,7 @@ function test() {
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 6).then(() => {
waitForNetworkEvents(aMonitor, 7).then(() => {
let requestItem = RequestsMenu.getItemAtIndex(5);
RequestsMenu.selectedItem = requestItem;

View File

@ -16,7 +16,7 @@ function test() {
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 6).then(() => {
waitForNetworkEvents(aMonitor, 7).then(() => {
let requestItem = RequestsMenu.getItemAtIndex(3);
RequestsMenu.selectedItem = requestItem;

View File

@ -13,7 +13,7 @@ function test() {
let { RequestsMenu } = NetMonitorView;
promise.all([
waitForNetworkEvents(aMonitor, 6),
waitForNetworkEvents(aMonitor, 7),
waitFor(aMonitor.panelWin, EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED)
]).then(() => {
info("Checking the image thumbnail when all items are shown.");

View File

@ -13,7 +13,7 @@ function test() {
let { RequestsMenu } = NetMonitorView;
promise.all([
waitForNetworkEvents(aMonitor, 6),
waitForNetworkEvents(aMonitor, 7),
waitFor(aMonitor.panelWin, EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED)
]).then(() => {
info("Checking the image thumbnail after a few requests were made...");

View File

@ -34,7 +34,9 @@
get("sjs_content-type-test-server.sjs?fmt=json", function() {
get("sjs_content-type-test-server.sjs?fmt=bogus", function() {
get("test-image.png?v=" + Math.random(), function() {
// Done.
get("sjs_content-type-test-server.sjs?fmt=gzip", function() {
// Done.
});
});
});
});

View File

@ -3,6 +3,33 @@
const { classes: Cc, interfaces: Ci } = Components;
function gzipCompressString(string, obs) {
let scs = Cc["@mozilla.org/streamConverters;1"]
.getService(Ci.nsIStreamConverterService);
let listener = Cc["@mozilla.org/network/stream-loader;1"]
.createInstance(Ci.nsIStreamLoader);
listener.init(obs);
let converter = scs.asyncConvertData("uncompressed", "gzip",
listener, null);
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"]
.createInstance(Ci.nsIStringInputStream);
stringStream.data = string;
converter.onStartRequest(null, null);
converter.onDataAvailable(null, null, stringStream, 0, string.length);
converter.onStopRequest(null, null, null);
}
function doubleGzipCompressString(string, observer) {
let observer2 = {
onStreamComplete: function(loader, context, status, length, result) {
let buffer = String.fromCharCode.apply(this, result);
gzipCompressString(buffer, observer);
}
};
gzipCompressString(string, observer2);
}
function handleRequest(request, response) {
response.processAsync();
@ -178,6 +205,25 @@ function handleRequest(request, response) {
response.finish();
break;
}
case "gzip": {
// Note: we're doing a double gzip encoding to test multiple
// converters in network monitor.
response.setStatusLine(request.httpVersion, status, "OK");
response.setHeader("Content-Type", "text/plain", false);
response.setHeader("Content-Encoding", "gzip\t ,gzip", false);
setCacheHeaders();
let observer = {
onStreamComplete: function(loader, context, status, length, result) {
let buffer = String.fromCharCode.apply(this, result);
response.setHeader("Content-Length", "" + buffer.length, false);
response.write(buffer);
response.finish();
}
};
let data = new Array(1000).join("Hello gzip!");
doubleGzipCompressString(data, observer);
break;
}
default: {
response.setStatusLine(request.httpVersion, 404, "Not Found");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);

View File

@ -203,9 +203,42 @@ NetworkResponseListener.prototype = {
*/
onStartRequest: function NRL_onStartRequest(aRequest)
{
// Converter will call this again, we should just ignore that.
if (this.request)
return;
this.request = aRequest;
this._getSecurityInfo();
this._findOpenResponse();
// We need to track the offset for the onDataAvailable calls where we pass the data
// from our pipe to the coverter.
this.offset = 0;
// In the multi-process mode, the conversion happens on the child side while we can
// only monitor the channel on the parent side. If the content is gzipped, we have
// to unzip it ourself. For that we use the stream converter services.
let channel = this.request;
if (channel instanceof Ci.nsIEncodedChannel &&
channel.contentEncodings &&
!channel.applyConversion) {
let encodingHeader = channel.getResponseHeader("Content-Encoding");
let scs = Cc["@mozilla.org/streamConverters;1"].
getService(Ci.nsIStreamConverterService);
let encodings = encodingHeader.split(/\s*\t*,\s*\t*/);
let nextListener = this;
let acceptedEncodings = ["gzip", "deflate", "x-gzip", "x-deflate"];
for (let i in encodings) {
// There can be multiple conversions applied
let enc = encodings[i].toLowerCase();
if (acceptedEncodings.indexOf(enc) > -1) {
this.converter = scs.asyncConvertData(enc, "uncompressed", nextListener, null);
nextListener = this.converter;
}
}
if (this.converter) {
this.converter.onStartRequest(this.request, null);
}
}
// Asynchronously wait for the data coming from the request.
this.setAsyncListener(this.sink.inputStream, this);
},
@ -364,6 +397,7 @@ NetworkResponseListener.prototype = {
this.httpActivity = null;
this.sink = null;
this.inputStream = null;
this.converter = null;
this.request = null;
this.owner = null;
},
@ -391,15 +425,18 @@ NetworkResponseListener.prototype = {
if (available != -1) {
if (available != 0) {
// Note that passing 0 as the offset here is wrong, but the
// onDataAvailable() method does not use the offset, so it does not
// matter.
this.onDataAvailable(this.request, null, aStream, 0, available);
if (this.converter) {
this.converter.onDataAvailable(this.request, null, aStream, this.offset, available);
} else {
this.onDataAvailable(this.request, null, aStream, this.offset, available);
}
}
this.offset += available;
this.setAsyncListener(aStream, this);
}
else {
this.onStreamClose();
this.offset = 0;
}
},
}; // NetworkResponseListener.prototype