mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 859170 - Fix for hang when trying to expand a very long message in the web console output; r=past
This commit is contained in:
parent
14529a750b
commit
6d467d6423
@ -120,6 +120,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_console_variables_view.js \
|
||||
browser_console_variables_view_while_debugging.js \
|
||||
browser_console.js \
|
||||
browser_longstring_hang.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
@ -221,6 +222,7 @@ MOCHITEST_BROWSER_FILES += \
|
||||
test-bug-821877-csperrors.html \
|
||||
test-bug-821877-csperrors.html^headers^ \
|
||||
test-eval-in-stackframe.html \
|
||||
test-bug-859170-longstring-hang.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
88
browser/devtools/webconsole/test/browser_longstring_hang.js
Normal file
88
browser/devtools/webconsole/test/browser_longstring_hang.js
Normal file
@ -0,0 +1,88 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that very long strings do not hang the browser.
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
let DebuggerServer = Cu.import("resource://gre/modules/devtools/dbg-server.jsm",
|
||||
{}).DebuggerServer;
|
||||
|
||||
addTab("http://example.com/browser/browser/devtools/webconsole/test/test-bug-859170-longstring-hang.html");
|
||||
|
||||
let hud = null;
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
|
||||
openConsole(null, performTest);
|
||||
}, true);
|
||||
|
||||
function performTest(aHud)
|
||||
{
|
||||
hud = aHud;
|
||||
|
||||
info("wait for the initial long string");
|
||||
|
||||
waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [
|
||||
{
|
||||
name: "find 'foobar', no 'foobaz', in long string output",
|
||||
text: "foobar",
|
||||
noText: "foobaz",
|
||||
category: CATEGORY_WEBDEV,
|
||||
longString: true,
|
||||
},
|
||||
],
|
||||
}).then(onInitialString);
|
||||
}
|
||||
|
||||
function onInitialString(aResults)
|
||||
{
|
||||
let msg = [...aResults[0].matched][0];
|
||||
ok(msg, "console.log result message element");
|
||||
|
||||
let clickable = msg.querySelector(".longStringEllipsis");
|
||||
ok(clickable, "long string ellipsis is shown");
|
||||
|
||||
scrollToVisible(clickable);
|
||||
|
||||
executeSoon(() => {
|
||||
EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
|
||||
|
||||
info("wait for long string expansion");
|
||||
|
||||
waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [
|
||||
{
|
||||
name: "find 'foobaz' after expand, but no 'boom!' at the end",
|
||||
text: "foobaz",
|
||||
noText: "boom!",
|
||||
category: CATEGORY_WEBDEV,
|
||||
longString: false,
|
||||
},
|
||||
{
|
||||
text: "too long to be displayed",
|
||||
longString: false,
|
||||
},
|
||||
],
|
||||
}).then(finishTest);
|
||||
});
|
||||
}
|
||||
|
||||
function scrollToVisible(aNode)
|
||||
{
|
||||
let richListBoxNode = aNode.parentNode;
|
||||
while (richListBoxNode.tagName != "richlistbox") {
|
||||
richListBoxNode = richListBoxNode.parentNode;
|
||||
}
|
||||
|
||||
let boxObject = richListBoxNode.scrollBoxObject;
|
||||
let nsIScrollBoxObject = boxObject.QueryInterface(Ci.nsIScrollBoxObject);
|
||||
nsIScrollBoxObject.ensureElementIsVisible(aNode);
|
||||
}
|
||||
}
|
@ -875,20 +875,28 @@ function waitForMessages(aOptions)
|
||||
let listenerAdded = false;
|
||||
let deferred = Promise.defer();
|
||||
|
||||
function checkText(aRule, aText)
|
||||
{
|
||||
let result;
|
||||
if (typeof aRule == "string") {
|
||||
result = aText.indexOf(aRule) > -1;
|
||||
}
|
||||
else if (aRule instanceof RegExp) {
|
||||
result = aRule.test(aText);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkMessage(aRule, aElement)
|
||||
{
|
||||
if (aRule.text) {
|
||||
let elemText = getMessageElementText(aElement);
|
||||
let matched = false;
|
||||
if (typeof aRule.text == "string") {
|
||||
matched = elemText.indexOf(aRule.text) > -1;
|
||||
}
|
||||
else if (aRule.text instanceof RegExp) {
|
||||
matched = aRule.text.test(elemText);
|
||||
}
|
||||
if (!matched) {
|
||||
return false;
|
||||
}
|
||||
let elemText = getMessageElementText(aElement);
|
||||
|
||||
if (aRule.text && !checkText(aRule.text, elemText)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aRule.noText && checkText(aRule.noText, elemText)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aRule.category) {
|
||||
@ -910,6 +918,11 @@ function waitForMessages(aOptions)
|
||||
}
|
||||
}
|
||||
|
||||
let longString = !!aElement.querySelector(".longStringEllipsis");
|
||||
if ("longString" in aRule && aRule.longString != longString) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let count = aRule.count || 1;
|
||||
if (!aRule.matched) {
|
||||
aRule.matched = new Set();
|
||||
@ -945,6 +958,7 @@ function waitForMessages(aOptions)
|
||||
if (rulesMatched == rules.length) {
|
||||
if (listenerAdded) {
|
||||
webconsole.ui.off("messages-added", onMessagesAdded);
|
||||
webconsole.ui.off("messages-updated", onMessagesAdded);
|
||||
}
|
||||
gPendingOutputTest--;
|
||||
deferred.resolve(rules);
|
||||
@ -964,7 +978,7 @@ function waitForMessages(aOptions)
|
||||
|
||||
for (let rule of rules) {
|
||||
if (!rule._ruleMatched) {
|
||||
console.log("failed to match rule: " + displayRule(rule));
|
||||
ok(false, "failed to match rule: " + displayRule(rule));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -980,6 +994,7 @@ function waitForMessages(aOptions)
|
||||
listenerAdded = true;
|
||||
registerCleanupFunction(testCleanup);
|
||||
webconsole.ui.on("messages-added", onMessagesAdded);
|
||||
webconsole.ui.on("messages-updated", onMessagesAdded);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head><meta charset="utf-8">
|
||||
<title>Web Console test for bug 859170 - very long strings hang the browser</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="application/javascript">
|
||||
(function() {
|
||||
var longString = "abbababazomglolztest";
|
||||
for (var i = 0; i < 10; i++) {
|
||||
longString += longString + longString;
|
||||
}
|
||||
|
||||
longString = "foobar" + (new Array(20000)).join("a") + "foobaz" +
|
||||
longString + "boom!";
|
||||
console.log(longString);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Web Console test for bug 859170 - very long strings hang the browser.</p>
|
||||
</body>
|
||||
</html>
|
@ -171,6 +171,9 @@ const FILTER_PREFS_PREFIX = "devtools.webconsole.filter.";
|
||||
// The minimum font size.
|
||||
const MIN_FONT_SIZE = 10;
|
||||
|
||||
// The maximum length of strings to be displayed by the Web Console.
|
||||
const MAX_LONG_STRING_LENGTH = 200000;
|
||||
|
||||
const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
|
||||
|
||||
/**
|
||||
@ -1319,7 +1322,7 @@ WebConsoleFrame.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Inform user that the Web Console API has been replaced by a script
|
||||
* Inform user that the window.console API has been replaced by a script
|
||||
* in a content page.
|
||||
*/
|
||||
logWarningAboutReplacedAPI: function WCF_logWarningAboutReplacedAPI()
|
||||
@ -1329,6 +1332,16 @@ WebConsoleFrame.prototype = {
|
||||
this.outputMessage(CATEGORY_JS, node);
|
||||
},
|
||||
|
||||
/**
|
||||
* Inform user that the string he tries to view is too long.
|
||||
*/
|
||||
logWarningAboutStringTooLong: function WCF_logWarningAboutStringTooLong()
|
||||
{
|
||||
let node = this.createMessageNode(CATEGORY_JS, SEVERITY_WARNING,
|
||||
l10n.getStr("longStringTooLong"));
|
||||
this.outputMessage(CATEGORY_JS, node);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the network events coming from the remote Web Console.
|
||||
*
|
||||
@ -1695,11 +1708,17 @@ WebConsoleFrame.prototype = {
|
||||
let hudIdSupportsString = WebConsoleUtils.supportsString(this.hudId);
|
||||
|
||||
// Output the current batch of messages.
|
||||
let newOrUpdatedNodes = new Set();
|
||||
let newMessages = new Set();
|
||||
let updatedMessages = new Set();
|
||||
for (let item of batch) {
|
||||
let result = this._outputMessageFromQueue(hudIdSupportsString, item);
|
||||
if (result) {
|
||||
newOrUpdatedNodes.add(result.isRepeated || result.node);
|
||||
if (result.isRepeated) {
|
||||
updatedMessages.add(result.isRepeated);
|
||||
}
|
||||
else {
|
||||
newMessages.add(result.node);
|
||||
}
|
||||
if (result.visible && result.node == this.outputNode.lastChild) {
|
||||
lastVisibleNode = result.node;
|
||||
}
|
||||
@ -1743,7 +1762,12 @@ WebConsoleFrame.prototype = {
|
||||
scrollBox.scrollTop -= oldScrollHeight - scrollBox.scrollHeight;
|
||||
}
|
||||
|
||||
this.emit("messages-added", newOrUpdatedNodes);
|
||||
if (newMessages.size) {
|
||||
this.emit("messages-added", newMessages);
|
||||
}
|
||||
if (updatedMessages.size) {
|
||||
this.emit("messages-updated", updatedMessages);
|
||||
}
|
||||
|
||||
// If the queue is not empty, schedule another flush.
|
||||
if (this._outputQueue.length > 0) {
|
||||
@ -2255,7 +2279,8 @@ WebConsoleFrame.prototype = {
|
||||
}
|
||||
|
||||
let longString = this.webConsoleClient.longString(aActor);
|
||||
longString.substring(longString.initial.length, longString.length,
|
||||
let toIndex = Math.min(longString.length, MAX_LONG_STRING_LENGTH);
|
||||
longString.substring(longString.initial.length, toIndex,
|
||||
function WCF__onSubstring(aResponse) {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("WCF__longStringClick substring failure: " +
|
||||
@ -2271,7 +2296,13 @@ WebConsoleFrame.prototype = {
|
||||
aMessage.category == CATEGORY_OUTPUT) {
|
||||
aMessage.clipboardText = aMessage.textContent;
|
||||
}
|
||||
});
|
||||
|
||||
this.emit("messages-updated", new Set([aMessage]));
|
||||
|
||||
if (toIndex != longString.length) {
|
||||
this.logWarningAboutStringTooLong();
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -3468,7 +3499,8 @@ JSTerm.prototype = {
|
||||
}
|
||||
|
||||
let client = this.webConsoleClient.longString(grip);
|
||||
client.substring(grip.initial.length, grip.length, (aResponse) => {
|
||||
let toIndex = Math.min(grip.length, MAX_LONG_STRING_LENGTH);
|
||||
client.substring(grip.initial.length, toIndex, (aResponse) => {
|
||||
if (aResponse.error) {
|
||||
Cu.reportError("JST__fetchVarLongString substring failure: " +
|
||||
aResponse.error + ": " + aResponse.message);
|
||||
@ -3479,6 +3511,10 @@ JSTerm.prototype = {
|
||||
aVar.setGrip(grip.initial + aResponse.substring);
|
||||
aVar.hideArrow();
|
||||
aVar._retrieved = true;
|
||||
|
||||
if (toIndex != grip.length) {
|
||||
this.hud.logWarningAboutStringTooLong();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -180,6 +180,10 @@ ToolboxWebconsole.tooltip=Web Console
|
||||
# from the server.
|
||||
longStringEllipsis=[…]
|
||||
|
||||
# LOCALIZATION NOTE (longStringTooLong): The string displayed after the user
|
||||
# tries to expand a long string.
|
||||
longStringTooLong=The string you are trying to view is too long to be displayed by the Web Console.
|
||||
|
||||
# LOCALIZATION NOTE (executeEmptyInput): This is displayed when the user tries
|
||||
# to execute code, but the input is empty.
|
||||
executeEmptyInput=No value to execute.
|
||||
|
Loading…
Reference in New Issue
Block a user