Bug 905226 - Identify custom JSON MIME-types as text. r=vporof

MIME types that can't be identified as textual are base64 encoded before
being shown in the Network Monitor tab of the developer tools. This text
detection wasn't identifying "custom" JSON MIME-types like
"application/x-bigcorp-api-json" as being JSON, and consequently they were
shown in a rather unhelpful base64 form.

This patch extends and liberalizes the isTextMimeType method to identify
these forms correctly.
This commit is contained in:
Felix Crux 2013-09-20 10:20:44 -04:00
parent a1c383eb7b
commit d01314ff24
7 changed files with 133 additions and 3 deletions

View File

@ -1864,8 +1864,11 @@ NetworkDetailsView.prototype = {
let { mimeType, text, encoding } = aResponse.content;
gNetwork.getString(text).then(aString => {
// Handle json.
if (mimeType.contains("/json")) {
// Handle json, which we tentatively identify by checking the MIME type
// for "json" after any word boundary. This works for the standard
// "application/json", and also for custom types like "x-bigcorp-json".
// This should be marginally more reliable than just looking for "json".
if (/\bjson/.test(mimeType)) {
let jsonpRegex = /^[a-zA-Z0-9_$]+\(|\)$/g; // JSONP with callback.
let sanitizedJSON = aString.replace(jsonpRegex, "");
let callbackPadding = aString.match(jsonpRegex);

View File

@ -24,6 +24,7 @@ MOCHITEST_BROWSER_FILES = \
browser_net_jsonp.js \
browser_net_json-long.js \
browser_net_json-malformed.js \
browser_net_json_custom_mime.js \
browser_net_timeline_ticks.js \
browser_net_sort-01.js \
browser_net_sort-02.js \
@ -50,6 +51,7 @@ MOCHITEST_BROWSER_FILES = \
html_jsonp-test-page.html \
html_json-long-test-page.html \
html_json-malformed-test-page.html \
html_json-custom-mime-test-page.html \
html_sorting-test-page.html \
html_filter-test-page.html \
html_infinite-get-page.html \

View File

@ -0,0 +1,78 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if JSON responses with unusal/custom MIME types are handled correctly.
*/
function test() {
initNetMonitor(JSON_CUSTOM_MIME_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, L10N, SourceEditor, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 1).then(() => {
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
"GET", CONTENT_TYPE_SJS + "?fmt=json-custom-mime", {
status: 200,
statusText: "OK",
type: "x-bigcorp-json",
fullMimeType: "text/x-bigcorp-json; charset=utf-8",
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
time: true
});
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[3]);
testResponseTab();
teardown(aMonitor).then(finish);
function testResponseTab() {
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"), 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.");
is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
"There should be 1 json scope displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-property").length, 2,
"There should be 2 json properties displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
"The empty notice should not be displayed in this tabpanel.");
let jsonScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
is(jsonScope.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
"greeting", "The first json property name was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .value")[0].getAttribute("value"),
"\"Hello oddly-named JSON!\"", "The first json property value was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
"__proto__", "The second json property name was incorrect.");
is(jsonScope.querySelectorAll(".variables-view-property .value")[1].getAttribute("value"),
"Object", "The second json property value was incorrect.");
}
});
aDebuggee.performRequests();
});
}

View File

@ -23,6 +23,7 @@ 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 JSON_CUSTOM_MIME_URL = EXAMPLE_URL + "html_json-custom-mime-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";

View File

@ -0,0 +1,35 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network Monitor test page</title>
</head>
<body>
<p>JSONP 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-custom-mime", function() {
// Done.
});
}
</script>
</body>
</html>

View File

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

View File

@ -420,7 +420,11 @@ let NetworkHelper = {
return true;
}
if (/^application\/[a-z-]+\+xml$/.test(aMimeType)) {
// XML and JSON often come with custom MIME types, so in addition to the
// standard "application/xml" and "application/json", we also look for
// variants like "application/x-bigcorp-xml" by checking for either string
// after any word boundary.
if (/^application\/[a-z-]+\b(xml|json)/.test(aMimeType)) {
return true;
}