Bug 1333385 - Fix base64 json in netmonitor. r=jdescottes a=gchang
☠☠ backed out by 2ec21157f2b5 ☠ ☠
authorAdrien Enault <schwartzmorn+bugzilla@gmail.com>
Thu, 26 Jan 2017 18:18:22 +0100
changeset 358913 7bae7aaeaead
parent 358912 9c0efc44eaa6
child 358914 b87d0d68c15a
push id10674
push usercbook@mozilla.com
push dateFri, 03 Feb 2017 11:15:54 +0000
treeherdermozilla-aurora@2cdc3dfa46c2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes, gchang
bugs1333385
milestone53.0a2
Bug 1333385 - Fix base64 json in netmonitor. r=jdescottes a=gchang
devtools/client/netmonitor/shared/components/response-panel.js
devtools/client/netmonitor/test/browser.ini
devtools/client/netmonitor/test/browser_net_json-b64.js
devtools/client/netmonitor/test/head.js
devtools/client/netmonitor/test/html_json-b64.html
devtools/client/netmonitor/test/sjs_content-type-test-server.sjs
--- a/devtools/client/netmonitor/shared/components/response-panel.js
+++ b/devtools/client/netmonitor/shared/components/response-panel.js
@@ -64,17 +64,21 @@ const ResponsePanel = createClass({
   // Additionally, we also directly parse the response text content to
   // verify whether it's json or not, to handle responses incorrectly
   // labeled as text/plain instead.
   isJSON(mimeType, response) {
     let json, error;
     try {
       json = JSON.parse(response);
     } catch (err) {
-      error = err;
+      try {
+        json = JSON.parse(atob(response));
+      } catch (err64) {
+        error = err;
+      }
     }
 
     if (/\bjson/.test(mimeType) || json) {
       // Extract the actual json substring in case this might be a "JSONP".
       // This regex basically parses a function call and captures the
       // function name and arguments in two separate groups.
       let jsonpRegex = /^\s*([\w$]+)\s*\(\s*([^]*)\s*\)\s*;?\s*$/;
       let [, jsonpCallback, jsonp] = response.match(jsonpRegex) || [];
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -11,16 +11,17 @@ support-files =
   html_image-tooltip-test-page.html
   html_cors-test-page.html
   html_custom-get-page.html
   html_cyrillic-test-page.html
   html_frame-test-page.html
   html_frame-subdocument.html
   html_filter-test-page.html
   html_infinite-get-page.html
+  html_json-b64.html
   html_json-custom-mime-test-page.html
   html_json-long-test-page.html
   html_json-malformed-test-page.html
   html_json-text-mime-test-page.html
   html_jsonp-test-page.html
   html_navigate-test-page.html
   html_params-test-page.html
   html_post-data-test-page.html
@@ -103,16 +104,17 @@ skip-if = (os == 'linux' && debug && bit
 skip-if = (os == 'linux' && debug && bits == 32) # Bug 1303439
 [browser_net_filter-02.js]
 [browser_net_filter-03.js]
 [browser_net_filter-04.js]
 [browser_net_footer-summary.js]
 [browser_net_html-preview.js]
 [browser_net_icon-preview.js]
 [browser_net_image-tooltip.js]
+[browser_net_json-b64.js]
 [browser_net_json-long.js]
 [browser_net_json-malformed.js]
 [browser_net_json_custom_mime.js]
 [browser_net_json_text_mime.js]
 [browser_net_jsonp.js]
 [browser_net_large-response.js]
 [browser_net_leak_on_tab_close.js]
 [browser_net_open_request_in_tab.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_json-b64.js
@@ -0,0 +1,62 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Tests if JSON responses encoded in base64 are handled correctly.
+ */
+
+add_task(function* () {
+  let { L10N } = require("devtools/client/netmonitor/l10n");
+  let { tab, monitor } = yield initNetMonitor(JSON_B64_URL);
+  info("Starting test... ");
+
+  let { document, NetMonitorView } = monitor.panelWin;
+  let { RequestsMenu } = NetMonitorView;
+
+  RequestsMenu.lazyUpdate = false;
+
+  let wait = waitForNetworkEvents(monitor, 1);
+  yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
+    content.wrappedJSObject.performRequests();
+  });
+  yield wait;
+
+  wait = waitForDOM(document, "#panel-3");
+  EventUtils.sendMouseEvent({ type: "mousedown" },
+    document.getElementById("details-pane-toggle"));
+  document.querySelector("#tab-3 a").click();
+  yield wait;
+
+  let tabpanel = document.querySelector("#panel-3");
+
+  is(tabpanel.querySelector(".response-error-header") === null, true,
+    "The response error header doesn't have the intended visibility.");
+  let jsonView = tabpanel.querySelector(".tree-section .treeLabel") || {};
+  is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
+    "The response json view has the intended visibility.");
+  is(tabpanel.querySelector(".editor-mount iframe") === null, true,
+    "The response editor doesn't have the intended visibility.");
+  is(tabpanel.querySelector(".response-image-box") === null, true,
+    "The response image box doesn't have the intended visibility.");
+
+  is(tabpanel.querySelectorAll(".tree-section").length, 1,
+    "There should be 1 tree sections displayed in this tabpanel.");
+  is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 1,
+    "There should be 1 json properties displayed in this tabpanel.");
+  is(tabpanel.querySelectorAll(".empty-notice").length, 0,
+    "The empty notice should not be displayed in this tabpanel.");
+
+  let labels = tabpanel
+    .querySelectorAll("tr:not(.tree-section) .treeLabelCell .treeLabel");
+  let values = tabpanel
+    .querySelectorAll("tr:not(.tree-section) .treeValueCell .objectBox");
+
+  is(labels[0].textContent, "greeting",
+    "The first json property name was incorrect.");
+  is(values[0].textContent, "\"This is a base 64 string.\"",
+    "The first json property value was incorrect.");
+
+  yield teardown(monitor);
+});
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -34,16 +34,17 @@ const POST_JSON_URL = EXAMPLE_URL + "htm
 const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
 const POST_RAW_WITH_HEADERS_URL = EXAMPLE_URL + "html_post-raw-with-headers-test-page.html";
 const PARAMS_URL = EXAMPLE_URL + "html_params-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 JSON_TEXT_MIME_URL = EXAMPLE_URL + "html_json-text-mime-test-page.html";
+const JSON_B64_URL = EXAMPLE_URL + "html_json-b64.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";
 const CUSTOM_GET_URL = EXAMPLE_URL + "html_custom-get-page.html";
 const SINGLE_GET_URL = EXAMPLE_URL + "html_single-get-page.html";
 const STATISTICS_URL = EXAMPLE_URL + "html_statistics-test-page.html";
 const CURL_URL = EXAMPLE_URL + "html_copy-as-curl.html";
 const CURL_UTILS_URL = EXAMPLE_URL + "html_curl-utils.html";
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/html_json-b64.html
@@ -0,0 +1,38 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
+    <meta http-equiv="Pragma" content="no-cache" />
+    <meta http-equiv="Expires" content="0" />
+    <title>Network Monitor test page</title>
+  </head>
+
+  <body>
+    <p>JSON b64 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-b64", function() {
+          // Done.
+        });
+      }
+    </script>
+  </body>
+
+</html>
--- a/devtools/client/netmonitor/test/sjs_content-type-test-server.sjs
+++ b/devtools/client/netmonitor/test/sjs_content-type-test-server.sjs
@@ -132,16 +132,24 @@ function handleRequest(request, response
         let fun = (params.filter((s) => s.includes("jsonp="))[0] || "").split("=")[1];
         response.setStatusLine(request.httpVersion, status, "OK");
         response.setHeader("Content-Type", "text/json; charset=utf-8", false);
         setCacheHeaders();
         response.write(" " + fun + " ( { \"greeting\": \"Hello weird JSONP!\" } ) ; ");
         response.finish();
         break;
       }
+      case "json-b64": {
+        response.setStatusLine(request.httpVersion, status, "OK");
+        response.setHeader("Content-Type", "text/json; charset=utf-8", false);
+        setCacheHeaders();
+        response.write(btoa("{ \"greeting\": \"This is a base 64 string.\" }"));
+        response.finish();
+        break;
+      }
       case "json-long": {
         let str = "{ \"greeting\": \"Hello long string JSON!\" },";
         response.setStatusLine(request.httpVersion, status, "OK");
         response.setHeader("Content-Type", "text/json; charset=utf-8", false);
         setCacheHeaders();
         response.write("[" + new Array(2048).join(str).slice(0, -1) + "]");
         response.finish();
         break;