Bug 1332949 - In the network panel copy posted data or response data in binary format doesn't work correctly. r?honza draft
authorLocke Chen <locke12456@gmail.com>
Wed, 24 May 2017 13:38:38 +0800
changeset 583507 f3335cfeb177849a711a148bca3878666352b4f7
parent 583335 96e18bec9fc8a5ce623c16167c12756bbe190d73
child 583508 9aaac1659f12ee291b7b46aeb3a63c94734af705
push id60416
push userbmo:locke12456@gmail.com
push dateWed, 24 May 2017 05:40:21 +0000
reviewershonza
bugs1332949
milestone55.0a1
Bug 1332949 - In the network panel copy posted data or response data in binary format doesn't work correctly. r?honza MozReview-Commit-ID: Kz4kj18U30Y
devtools/client/netmonitor/src/request-list-context-menu.js
devtools/client/netmonitor/src/utils/request-utils.js
--- a/devtools/client/netmonitor/src/request-list-context-menu.js
+++ b/devtools/client/netmonitor/src/request-list-context-menu.js
@@ -18,16 +18,17 @@ const {
   getSelectedRequest,
   getSortedRequests,
 } = require("./selectors/index");
 const { L10N } = require("./utils/l10n");
 const { showMenu } = require("./utils/menu");
 const {
   getUrlQuery,
   parseQueryString,
+  isBinary,
 } = require("./utils/request-utils");
 
 function RequestListContextMenu({
   cloneSelectedRequest,
   openStatistics,
 }) {
   this.cloneSelectedRequest = cloneSelectedRequest;
   this.openStatistics = openStatistics;
@@ -228,17 +229,17 @@ RequestListContextMenu.prototype = {
     let params = getUrlQuery(this.selectedRequest.url).split("&");
     copyString(params.join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n"));
   },
 
   /**
    * Copy the request form data parameters (or raw payload) from
    * the currently selected item.
    */
-  copyPostData() {
+  async copyPostData() {
     let { formDataSections, requestPostData } = this.selectedRequest;
     let params = [];
 
     // Try to extract any form data parameters.
     formDataSections.forEach(section => {
       let paramsArray = parseQueryString(section);
       if (paramsArray) {
         params = [...params, ...paramsArray];
@@ -247,20 +248,27 @@ RequestListContextMenu.prototype = {
 
     let string = params
       .map(param => param.name + (param.value ? "=" + param.value : ""))
       .join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n");
 
     // Fall back to raw payload.
     if (!string) {
       string = requestPostData.postData.text;
+      let verify = await isBinary(string);
+
+      if (verify) {
+        string = JSON.stringify(string);
+      }
+
       if (Services.appinfo.OS !== "WINNT") {
         string = string.replace(/\r/g, "");
       }
     }
+
     copyString(string);
   },
 
   /**
    * Copy a cURL command from the currently selected item.
    */
   copyAsCurl() {
     let selected = this.selectedRequest;
--- a/devtools/client/netmonitor/src/utils/request-utils.js
+++ b/devtools/client/netmonitor/src/utils/request-utils.js
@@ -335,16 +335,52 @@ function getEndTime(item, firstRequestSt
  * a firstRequestStartedMillis.
  */
 function getResponseTime(item, firstRequestStartedMillis = 0) {
   let { startedMillis, totalTime, eventTimings = { timings: {} } } = item;
   return startedMillis + totalTime - firstRequestStartedMillis -
     eventTimings.timings.receive;
 }
 
+function between(num, first, last) {
+  return num >= first && num <= last;
+}
+
+function nonprintable(code) {
+  return between(code, 0, 8) || code == 0xb || between(code, 0xe, 0x1f) || code == 0x7f;
+}
+
+async function isBinary(string) {
+  let blob = new Blob([string], {type: "application/octet-binary"});
+  return new Promise((resolve, reject) => {
+    let reader = new FileReader();
+
+    reader.onerror = (event) => {
+      reject(event);
+      return false;
+    };
+
+    reader.onloadend = (event) => {
+      let buff = reader.result;
+      let view = new Uint8Array(buff);
+
+      for (let count = 0; count < view.length; count++) {
+        if (nonprintable(view[count])) {
+          resolve(true);
+          return true;
+        }
+      }
+      resolve(false);
+      return false;
+    };
+
+    reader.readAsArrayBuffer(blob);
+  });
+}
+
 module.exports = {
   getFormDataSections,
   fetchHeaders,
   formDataURI,
   writeHeaderText,
   decodeUnicodeUrl,
   getAbbreviatedMimeType,
   getEndTime,
@@ -356,9 +392,10 @@ module.exports = {
   getUrlHost,
   getUrlHostName,
   getUrlQuery,
   getUrlScheme,
   parseQueryString,
   parseFormData,
   propertiesEqual,
   ipToLong,
+  isBinary,
 };