Bug 1431758 - do not use netmonitor data to fetch stylesheets over 1MB;r=jryans
MozReview-Commit-ID: Gz6dRLiLREm
--- a/devtools/client/styleeditor/test/browser.ini
+++ b/devtools/client/styleeditor/test/browser.ini
@@ -28,16 +28,17 @@ support-files =
resources_inpage1.css
resources_inpage2.css
selector-highlighter.html
simple.css
simple.css.gz
simple.css.gz^headers^
simple.gz.html
simple.html
+ sjs_huge-css-server.sjs
sourcemap-css/contained.css
sourcemap-css/sourcemaps.css
sourcemap-css/sourcemaps.css.map
sourcemap-css/media-rules.css
sourcemap-css/media-rules.css.map
sourcemap-css/test-bootstrap-scss.css
sourcemap-css/test-stylus.css
sourcemap-sass/sourcemaps.scss
--- a/devtools/client/styleeditor/test/browser_styleeditor_fetch-from-netmonitor.js
+++ b/devtools/client/styleeditor/test/browser_styleeditor_fetch-from-netmonitor.js
@@ -32,22 +32,31 @@ add_task(function* () {
info("Waiting for the sources to be loaded.");
yield ui.editors[0].getSourceEditor();
yield ui.selectStyleSheet(ui.editors[1].styleSheet);
yield ui.editors[1].getSourceEditor();
info("Checking Netmonitor contents.");
let shortRequests = [];
let longRequests = [];
+ let hugeRequests = [];
for (let item of getSortedRequests(store.getState())) {
if (item.url.endsWith("doc_short_string.css")) {
shortRequests.push(item);
}
if (item.url.endsWith("doc_long_string.css")) {
longRequests.push(item);
}
+ if (item.url.endsWith("sjs_huge-css-server.sjs")) {
+ hugeRequests.push(item);
+ }
}
is(shortRequests.length, 1,
"Got one request for doc_short_string.css after Style Editor was loaded.");
is(longRequests.length, 1,
"Got one request for doc_long_string.css after Style Editor was loaded.");
+
+ // Requests with a response body size greater than 1MB cannot be fetched from the
+ // netmonitor, the style editor should perform a separate request.
+ is(hugeRequests.length, 2,
+ "Got two requests for sjs_huge-css-server.sjs after Style Editor was loaded.");
});
--- a/devtools/client/styleeditor/test/doc_fetch_from_netmonitor.html
+++ b/devtools/client/styleeditor/test/doc_fetch_from_netmonitor.html
@@ -1,11 +1,13 @@
<!doctype html>
<html>
<head>
<title>Fetch from netmonitor testcase</title>
<link rel="stylesheet" charset="UTF-8" type="text/css" media="screen" href="doc_short_string.css"/>
<link rel="stylesheet" charset="UTF-8" type="text/css" media="screen" href="doc_long_string.css"/>
+ <!-- This last CSS is generated by a SJS server to avoid adding a 300,000 lines stylesheet to the codebase. -->
+ <link rel="stylesheet" charset="UTF-8" type="text/css" media="screen" href="sjs_huge-css-server.sjs"/>
</head>
<body>
<div>Fetch from netmonitor</div>
</body>
</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/styleeditor/test/sjs_huge-css-server.sjs
@@ -0,0 +1,18 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function handleRequest(request, response) {
+ response.setStatusLine(request.httpVersion, 200, "Och Aye");
+
+ response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+ response.setHeader("Pragma", "no-cache");
+ response.setHeader("Expires", "0");
+ response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
+
+ // Taken from devtools/shared/webconsole/network-monitor
+ const NETMONITOR_LIMIT = 1048576;
+
+ // 2 * NETMONITOR_LIMIT reaches the exact limit for the netmonitor
+ // 3 * NETMONITOR_LIMIT makes sure we go past it.
+ response.write("x".repeat(3 * NETMONITOR_LIMIT));
+}
--- a/devtools/server/actors/stylesheets.js
+++ b/devtools/server/actors/stylesheets.js
@@ -486,17 +486,17 @@ var StyleSheetActor = protocol.ActorClas
if (!consoleActor) {
return null;
}
let request = consoleActor.getNetworkEventActorForURL(href);
if (!request) {
return null;
}
let content = request._response.content;
- if (request._discardResponseBody || !content) {
+ if (request._discardResponseBody || request._truncated || !content) {
return null;
}
if (content.text.type != "longString") {
// For short strings, the text is available directly.
return {
content: content.text,
contentType: content.mimeType,
};
--- a/devtools/server/actors/webconsole.js
+++ b/devtools/server/actors/webconsole.js
@@ -2057,16 +2057,17 @@ NetworkEventActor.prototype =
!!(this._stackTrace && this._stackTrace.length);
for (let prop of ["method", "url", "httpVersion", "headersSize"]) {
this._request[prop] = networkEvent[prop];
}
this._discardRequestBody = networkEvent.discardRequestBody;
this._discardResponseBody = networkEvent.discardResponseBody;
+ this._truncated = false;
this._private = networkEvent.private;
},
/**
* The "getRequestHeaders" packet type handler.
*
* @return object
* The response packet - network request headers.
@@ -2358,35 +2359,39 @@ NetworkEventActor.prototype =
this.conn.send(packet);
},
/**
* Add network response content.
*
* @param object content
* The response content.
- * @param boolean discardedResponseBody
- * Tells if the response content was recorded or not.
+ * @param object
+ * - boolean discardedResponseBody
+ * Tells if the response content was recorded or not.
+ * - boolean truncated
+ * Tells if the some of the response content is missing.
*/
- addResponseContent: function (content, discardedResponseBody) {
+ addResponseContent: function (content, {discardResponseBody, truncated}) {
+ this._truncated = truncated;
this._response.content = content;
content.text = this.parent._createStringGrip(content.text);
if (typeof content.text == "object") {
this._longStringActors.add(content.text);
}
let packet = {
from: this.actorID,
type: "networkEventUpdate",
updateType: "responseContent",
mimeType: content.mimeType,
contentSize: content.size,
encoding: content.encoding,
transferredSize: content.transferredSize,
- discardResponseBody: discardedResponseBody,
+ discardResponseBody,
};
this.conn.send(packet);
},
/**
* Add network event timing information.
*
--- a/devtools/shared/webconsole/network-monitor.js
+++ b/devtools/shared/webconsole/network-monitor.js
@@ -274,16 +274,18 @@ exports.StackTraceCollector = StackTrace
* HttpActivity object associated with this request. See NetworkMonitor
* for more information.
*/
function NetworkResponseListener(owner, httpActivity) {
this.owner = owner;
this.receivedData = "";
this.httpActivity = httpActivity;
this.bodySize = 0;
+ // Indicates if the response had a size greater than RESPONSE_BODY_LIMIT.
+ this.truncated = false;
// Note that this is really only needed for the non-e10s case.
// See bug 1309523.
let channel = this.httpActivity.channel;
this._wrappedNotificationCallbacks = channel.notificationCallbacks;
channel.notificationCallbacks = this;
}
NetworkResponseListener.prototype = {
@@ -407,20 +409,23 @@ NetworkResponseListener.prototype = {
* @param unsigned long count
*/
onDataAvailable: function (request, context, inputStream, offset, count) {
this._findOpenResponse();
let data = NetUtil.readInputStreamToString(inputStream, count);
this.bodySize += count;
- if (!this.httpActivity.discardResponseBody &&
- this.receivedData.length < RESPONSE_BODY_LIMIT) {
- this.receivedData +=
- NetworkHelper.convertToUnicode(data, request.contentCharset);
+ if (!this.httpActivity.discardResponseBody) {
+ if (this.receivedData.length < RESPONSE_BODY_LIMIT) {
+ this.receivedData +=
+ NetworkHelper.convertToUnicode(data, request.contentCharset);
+ } else {
+ this.truncated = true;
+ }
}
},
/**
* See documentation at
* https://developer.mozilla.org/En/NsIRequestObserver
*
* @param nsIRequest request
@@ -635,17 +640,20 @@ NetworkResponseListener.prototype = {
if (response.mimeType && this.request.contentCharset) {
response.mimeType += "; charset=" + this.request.contentCharset;
}
this.receivedData = "";
this.httpActivity.owner.addResponseContent(
response,
- this.httpActivity.discardResponseBody
+ {
+ discardResponseBody: this.httpActivity.discardResponseBody,
+ truncated: this.truncated
+ }
);
this._wrappedNotificationCallbacks = null;
this.httpActivity = null;
this.sink = null;
this.inputStream = null;
this.converter = null;
this.request = null;