Bug 859055 - Display JSON as plain text when encountering errors when parsing, r=rcampbell

This commit is contained in:
Victor Porof 2013-06-12 10:37:46 +03:00
Родитель 22652cc944
Коммит 80155ced75
16 изменённых файлов: 192 добавлений и 18 удалений

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

@ -1315,6 +1315,7 @@ NetworkDetailsView.prototype = {
$("#request-params-box").setAttribute("flex", "1");
$("#request-params-box").hidden = false;
$("#request-post-data-textarea-box").hidden = true;
$("#response-content-info-header").hidden = true;
$("#response-content-json-box").hidden = true;
$("#response-content-textarea-box").hidden = true;
$("#response-content-image-box").hidden = true;
@ -1612,18 +1613,42 @@ NetworkDetailsView.prototype = {
gNetwork.getString(text).then((aString) => {
// Handle json.
if (mimeType.contains("/json")) {
$("#response-content-json-box").hidden = false;
let jsonpRegex = /^[a-zA-Z0-9_$]+\(|\)$/g; // JSONP with callback.
let sanitizedJSON = aString.replace(jsonpRegex, "");
let callbackPadding = aString.match(jsonpRegex);
let jsonScopeName = callbackPadding
? L10N.getFormatStr("jsonpScopeName", callbackPadding[0].slice(0, -1))
: L10N.getStr("jsonScopeName");
// Make sure this is an valid JSON object first. If so, nicely display
// the parsing results in a variables view. Otherwise, simply show
// the contents as plain text.
try {
var jsonObject = JSON.parse(sanitizedJSON);
} catch (e) {
var parsingError = e;
}
let jsonScope = this._json.addScope(jsonScopeName);
jsonScope.addVar().populate(JSON.parse(sanitizedJSON), { expanded: true });
jsonScope.expanded = true;
// Valid JSON.
if (jsonObject) {
$("#response-content-json-box").hidden = false;
let jsonScopeName = callbackPadding
? L10N.getFormatStr("jsonpScopeName", callbackPadding[0].slice(0, -1))
: L10N.getStr("jsonScopeName");
let jsonScope = this._json.addScope(jsonScopeName);
jsonScope.addVar().populate(jsonObject, { expanded: true });
jsonScope.expanded = true;
}
// Malformed JSON.
else {
$("#response-content-textarea-box").hidden = false;
NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
aEditor.setMode(SourceEditor.MODES.JAVASCRIPT);
aEditor.setText(aString);
});
let infoHeader = $("#response-content-info-header");
infoHeader.setAttribute("value", parsingError);
infoHeader.setAttribute("tooltiptext", parsingError);
infoHeader.hidden = false;
}
}
// Handle images.
else if (mimeType.contains("image/")) {

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

@ -272,6 +272,7 @@
<tabpanel id="response-tabpanel"
class="tabpanel-content">
<vbox flex="1">
<label id="response-content-info-header"/>
<vbox id="response-content-json-box" flex="1" hidden="true">
<vbox id="response-content-json" flex="1"/>
</vbox>

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

@ -31,6 +31,7 @@ MOCHITEST_BROWSER_TESTS = \
browser_net_post-data-02.js \
browser_net_jsonp.js \
browser_net_json-long.js \
browser_net_json-malformed.js \
browser_net_timeline_ticks.js \
browser_net_sort-01.js \
browser_net_sort-02.js \
@ -55,6 +56,7 @@ MOCHITEST_BROWSER_PAGES = \
html_post-raw-test-page.html \
html_jsonp-test-page.html \
html_json-long-test-page.html \
html_json-malformed-test-page.html \
html_sorting-test-page.html \
html_filter-test-page.html \
html_infinite-get-page.html \

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

@ -109,14 +109,15 @@ function test() {
"The response tab in the network details pane should be selected.");
function checkVisibility(aBox) {
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), true,
"The response info header doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), aBox != "json",
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), aBox != "textarea",
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), aBox != "image",
"The response content image box doesn't have the intended visibility.");

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

@ -46,14 +46,15 @@ function test() {
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), true,
"The response info header doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), false,
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), true,
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), true,
"The response content image box doesn't have the intended visibility.");

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

@ -0,0 +1,71 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if malformed JSON responses are handled correctly.
*/
function test() {
initNetMonitor(JSON_MALFORMED_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, SourceEditor, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 1).then(() => {
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
"GET", CONTENT_TYPE_SJS + "?fmt=json-malformed", {
status: 200,
statusText: "OK",
type: "json",
fullMimeType: "text/json; charset=utf-8"
});
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[3]);
let tab = document.querySelectorAll("#details-pane tab")[3];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), false,
"The response info header doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-info-header")
.getAttribute("value"),
"SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data",
"The response info header doesn't have the intended value attribute.");
is(tabpanel.querySelector("#response-content-info-header")
.getAttribute("tooltiptext"),
"SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data",
"The response info header doesn't have the intended tooltiptext attribute.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), true,
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), false,
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), true,
"The response content image box doesn't have the intended visibility.");
NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
is(aEditor.getText(), "{ \"greeting\": \"Hello malformed JSON!\" },",
"The text shown in the source editor is incorrect.");
is(aEditor.getMode(), SourceEditor.MODES.JAVASCRIPT,
"The mode active in the source editor is incorrect.");
teardown(aMonitor).then(finish);
});
});
aDebuggee.performRequests();
});
}

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

@ -40,14 +40,15 @@ function test() {
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), true,
"The response info header doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), false,
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), true,
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), true,
"The response content image box doesn't have the intended visibility.");

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

@ -61,7 +61,6 @@ function test() {
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), !aBox.contains("params"),
"The request params box doesn't have the indended visibility.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), !aBox.contains("textarea"),
"The request post data textarea box doesn't have the indended visibility.");

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

@ -163,7 +163,6 @@ function test() {
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), false,
"The request params box should not be hidden.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), true,
"The request post data textarea box should be hidden.");
@ -179,14 +178,15 @@ function test() {
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), true,
"The response info header should be hidden.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), true,
"The response content json box should be hidden.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), false,
"The response content textarea box should not be hidden.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), true,
"The response content image box should be hidden.");

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

@ -144,7 +144,6 @@ function test() {
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), false,
"The request params box should not be hidden.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), true,
"The request post data textarea box should be hidden.");

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

@ -22,6 +22,7 @@ const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
const JSON_LONG_URL = EXAMPLE_URL + "html_json-long-test-page.html";
const JSON_MALFORMED_URL = EXAMPLE_URL + "html_json-malformed-test-page.html";
const SORTING_URL = EXAMPLE_URL + "html_sorting-test-page.html";
const FILTERING_URL = EXAMPLE_URL + "html_filter-test-page.html";
const INFINITE_GET_URL = EXAMPLE_URL + "html_infinite-get-page.html";

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

@ -0,0 +1,33 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network Monitor test page</title>
</head>
<body>
<p>JSON malformed test</p>
<script type="text/javascript">
function get(aAddress, aCallback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", aAddress, true);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
aCallback();
}
};
xhr.send(null);
}
function performRequests() {
get("sjs_content-type-test-server.sjs?fmt=json-malformed", function() {
// Done.
});
}
</script>
</body>
</html>

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

@ -78,6 +78,13 @@ function handleRequest(request, response) {
response.finish();
break;
}
case "json-malformed": {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/json; charset=utf-8", false);
response.write("{ \"greeting\": \"Hello malformed JSON!\" },");
response.finish();
break;
}
case "font": {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "font/woff", false);

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

@ -381,6 +381,17 @@ box.requests-menu-status[code^="5"] {
/* Response tabpanel */
#response-content-info-header {
background:
url(background-noise-toolbar.png),
linear-gradient(hsl(0,61%,40%), hsl(0,61%,31%)) repeat-x top left;
box-shadow:
inset 0 1px 0 hsla(210,40%,83%,.15),
inset 0 -1px 0 hsla(210,40%,83%,.05);
margin: 0;
padding: 5px 8px;
}
#response-content-image-box {
padding-top: 10px;
padding-bottom: 10px;

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

@ -381,6 +381,17 @@ box.requests-menu-status[code^="5"] {
/* Response tabpanel */
#response-content-info-header {
background:
url(background-noise-toolbar.png),
linear-gradient(hsl(0,61%,40%), hsl(0,61%,31%)) repeat-x top left;
box-shadow:
inset 0 1px 0 hsla(210,40%,83%,.15),
inset 0 -1px 0 hsla(210,40%,83%,.05);
margin: 0;
padding: 5px 8px;
}
#response-content-image-box {
padding-top: 10px;
padding-bottom: 10px;

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

@ -381,6 +381,17 @@ box.requests-menu-status[code^="5"] {
/* Response tabpanel */
#response-content-info-header {
background:
url(background-noise-toolbar.png),
linear-gradient(hsl(0,61%,40%), hsl(0,61%,31%)) repeat-x top left;
box-shadow:
inset 0 1px 0 hsla(210,40%,83%,.15),
inset 0 -1px 0 hsla(210,40%,83%,.05);
margin: 0;
padding: 5px 8px;
}
#response-content-image-box {
padding-top: 10px;
padding-bottom: 10px;