Bug 1356867 - Add scheme column to netmonitor. r?ntim draft
authorVangelis Katsikaros <vkatsikaros@gmail.com>
Mon, 01 May 2017 12:11:46 +0300
changeset 570867 e61c3dd2d55fa23cdb4e92f0a81fc0f8bbd03414
parent 570708 2fe636103d7167f3a5d57f61bd19fddcc878ca3c
child 626590 44bf0b96941c4f10e43993478c5362215d0edfa7
push id56600
push uservkatsikaros@gmail.com
push dateMon, 01 May 2017 12:39:57 +0000
reviewersntim
bugs1356867
milestone55.0a1
Bug 1356867 - Add scheme column to netmonitor. r?ntim MozReview-Commit-ID: 8ZkD9WRd0VQ
devtools/client/locales/en-US/netmonitor.properties
devtools/client/netmonitor/index.js
devtools/client/netmonitor/src/assets/styles/netmonitor.css
devtools/client/netmonitor/src/components/moz.build
devtools/client/netmonitor/src/components/request-list-column-scheme.js
devtools/client/netmonitor/src/components/request-list-item.js
devtools/client/netmonitor/src/constants.js
devtools/client/netmonitor/src/reducers/ui.js
devtools/client/netmonitor/src/utils/filter-text-utils.js
devtools/client/netmonitor/src/utils/request-utils.js
devtools/client/netmonitor/src/utils/sort-predicates.js
devtools/client/netmonitor/test/head.js
devtools/client/preferences/devtools.js
--- a/devtools/client/locales/en-US/netmonitor.properties
+++ b/devtools/client/locales/en-US/netmonitor.properties
@@ -490,16 +490,20 @@ netmonitor.toolbar.type=Type
 netmonitor.toolbar.cookies=Cookies
 
 # LOCALIZATION NOTE (netmonitor.toolbar.setCookies): This is the label displayed
 # in the network table toolbar, above the "set cookies" column.
 # Set-Cookie is a HTTP response header. This string is the plural form of it.
 # See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
 netmonitor.toolbar.setCookies=Set-Cookies
 
+# LOCALIZATION NOTE (netmonitor.toolbar.cookies): This is the label displayed
+# in the network table toolbar, above the "scheme" column.
+netmonitor.toolbar.scheme=Scheme
+
 # LOCALIZATION NOTE (netmonitor.toolbar.transferred): This is the label displayed
 # in the network table toolbar, above the "transferred" column, which is the
 # compressed / encoded size.
 netmonitor.toolbar.transferred=Transferred
 
 # LOCALIZATION NOTE (netmonitor.toolbar.contentSize): This is the label displayed
 # in the network table toolbar, above the "size" column, which is the
 # uncompressed / decoded size.
--- a/devtools/client/netmonitor/index.js
+++ b/devtools/client/netmonitor/index.js
@@ -19,17 +19,17 @@ const { configureStore } = require("./sr
 
 require("./src/assets/styles/netmonitor.css");
 
 EventEmitter.decorate(window);
 
 pref("devtools.netmonitor.enabled", true);
 pref("devtools.netmonitor.filters", "[\"all\"]");
 pref("devtools.netmonitor.hiddenColumns",
-     "[\"cookies\",\"protocol\",\"remoteip\",\"setCookies\"]");
+     "[\"cookies\",\"protocol\",\"remoteip\",\"scheme\",\"setCookies\"]");
 pref("devtools.netmonitor.panes-network-details-width", 550);
 pref("devtools.netmonitor.panes-network-details-height", 450);
 pref("devtools.netmonitor.har.defaultLogDir", "");
 pref("devtools.netmonitor.har.defaultFileName", "Archive %date");
 pref("devtools.netmonitor.har.jsonp", false);
 pref("devtools.netmonitor.har.jsonpCallback", "");
 pref("devtools.netmonitor.har.includeResponseBodies", true);
 pref("devtools.netmonitor.har.compress", false);
--- a/devtools/client/netmonitor/src/assets/styles/netmonitor.css
+++ b/devtools/client/netmonitor/src/assets/styles/netmonitor.css
@@ -442,16 +442,22 @@ body,
 }
 
 /* Set Cookies column */
 
 .requests-list-set-cookies {
   width: 8%;
 }
 
+/* Scheme column */
+
+.requests-list-scheme {
+  width: 8%;
+}
+
 /* Domain column */
 
 .requests-list-domain {
   width: 13%;
 }
 
 .requests-list-domain.requests-list-column {
   text-align: start;
--- a/devtools/client/netmonitor/src/components/moz.build
+++ b/devtools/client/netmonitor/src/components/moz.build
@@ -15,16 +15,17 @@ DevToolsModules(
     'request-list-column-cause.js',
     'request-list-column-content-size.js',
     'request-list-column-cookies.js',
     'request-list-column-domain.js',
     'request-list-column-file.js',
     'request-list-column-method.js',
     'request-list-column-protocol.js',
     'request-list-column-remote-ip.js',
+    'request-list-column-scheme.js',
     'request-list-column-set-cookies.js',
     'request-list-column-status.js',
     'request-list-column-transferred-size.js',
     'request-list-column-type.js',
     'request-list-column-waterfall.js',
     'request-list-content.js',
     'request-list-empty-notice.js',
     'request-list-header.js',
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/src/components/request-list-column-scheme.js
@@ -0,0 +1,39 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {
+  createClass,
+  DOM,
+  PropTypes,
+} = require("devtools/client/shared/vendor/react");
+
+const { div } = DOM;
+
+const RequestListColumnScheme = createClass({
+  displayName: "RequestListColumnScheme",
+
+  propTypes: {
+    item: PropTypes.object.isRequired,
+  },
+
+  shouldComponentUpdate(nextProps) {
+    return this.props.item.urlDetails.scheme !== nextProps.item.urlDetails.scheme;
+  },
+
+  render() {
+    const { urlDetails } = this.props.item;
+    return (
+      div({
+        className: "requests-list-column requests-list-scheme",
+        title: urlDetails.scheme
+      },
+        urlDetails.scheme
+      )
+    );
+  }
+});
+
+module.exports = RequestListColumnScheme;
--- a/devtools/client/netmonitor/src/components/request-list-item.js
+++ b/devtools/client/netmonitor/src/components/request-list-item.js
@@ -17,16 +17,17 @@ const { propertiesEqual } = require("../
 const RequestListColumnCause = createFactory(require("./request-list-column-cause"));
 const RequestListColumnContentSize = createFactory(require("./request-list-column-content-size"));
 const RequestListColumnCookies = createFactory(require("./request-list-column-cookies"));
 const RequestListColumnDomain = createFactory(require("./request-list-column-domain"));
 const RequestListColumnFile = createFactory(require("./request-list-column-file"));
 const RequestListColumnMethod = createFactory(require("./request-list-column-method"));
 const RequestListColumnProtocol = createFactory(require("./request-list-column-protocol"));
 const RequestListColumnRemoteIP = createFactory(require("./request-list-column-remote-ip"));
+const RequestListColumnScheme = createFactory(require("./request-list-column-scheme"));
 const RequestListColumnSetCookies = createFactory(require("./request-list-column-set-cookies"));
 const RequestListColumnStatus = createFactory(require("./request-list-column-status"));
 const RequestListColumnTransferredSize = createFactory(require("./request-list-column-transferred-size"));
 const RequestListColumnType = createFactory(require("./request-list-column-type"));
 const RequestListColumnWaterfall = createFactory(require("./request-list-column-waterfall"));
 
 const { div } = DOM;
 
@@ -130,16 +131,17 @@ const RequestListItem = createClass({
         tabIndex: 0,
         onContextMenu,
         onMouseDown,
       },
         columns.get("status") && RequestListColumnStatus({ item }),
         columns.get("method") && RequestListColumnMethod({ item }),
         columns.get("file") && RequestListColumnFile({ item }),
         columns.get("protocol") && RequestListColumnProtocol({ item }),
+        columns.get("scheme") && RequestListColumnScheme({ item }),
         columns.get("domain") && RequestListColumnDomain({ item, onSecurityIconClick }),
         columns.get("remoteip") && RequestListColumnRemoteIP({ item }),
         columns.get("cause") && RequestListColumnCause({ item, onCauseBadgeClick }),
         columns.get("type") && RequestListColumnType({ item }),
         columns.get("cookies") && RequestListColumnCookies({ item }),
         columns.get("setCookies") && RequestListColumnSetCookies({ item }),
         columns.get("transferred") && RequestListColumnTransferredSize({ item }),
         columns.get("contentSize") && RequestListColumnContentSize({ item }),
--- a/devtools/client/netmonitor/src/constants.js
+++ b/devtools/client/netmonitor/src/constants.js
@@ -113,16 +113,20 @@ const HEADERS = [
     name: "file",
     canFilter: false,
   },
   {
     name: "protocol",
     canFilter: true,
   },
   {
+    name: "scheme",
+    canFilter: true,
+  },
+  {
     name: "domain",
     canFilter: true,
   },
   {
     name: "remoteip",
     canFilter: true,
     filterKey: "remote-ip",
   },
--- a/devtools/client/netmonitor/src/reducers/ui.js
+++ b/devtools/client/netmonitor/src/reducers/ui.js
@@ -18,16 +18,17 @@ const {
   WATERFALL_RESIZE,
 } = require("../constants");
 
 const Columns = I.Record({
   status: true,
   method: true,
   file: true,
   protocol: false,
+  scheme: false,
   domain: true,
   remoteip: false,
   cause: true,
   type: true,
   cookies: false,
   setCookies: false,
   transferred: true,
   contentSize: true,
--- a/devtools/client/netmonitor/src/utils/filter-text-utils.js
+++ b/devtools/client/netmonitor/src/utils/filter-text-utils.js
@@ -33,17 +33,16 @@
 const { HEADERS } = require("../constants");
 const { getFormattedIPAndPort } = require("./format-utils");
 const HEADER_FILTERS = HEADERS
   .filter(h => h.canFilter)
   .map(h => h.filterKey || h.name);
 
 const FILTER_FLAGS = [
   ...HEADER_FILTERS,
-  "scheme",
   "set-cookie-domain",
   "set-cookie-name",
   "set-cookie-value",
   "mime-type",
   "larger-than",
   "is",
   "has-response-header",
   "regexp",
@@ -177,18 +176,17 @@ function isFlagFilterMatch(item, { type,
       if (value === "from-cache" ||
           value === "cached") {
         match = item.fromCache || item.status === "304";
       } else if (value === "running") {
         match = !item.status;
       }
       break;
     case "scheme":
-      let scheme = new URL(item.url).protocol.replace(":", "").toLowerCase();
-      match = scheme === value;
+      match = item.urlDetails.scheme === value;
       break;
     case "regexp":
       try {
         let pattern = new RegExp(value);
         match = pattern.test(item.url);
       } catch (e) {
         match = false;
       }
--- a/devtools/client/netmonitor/src/utils/request-utils.js
+++ b/devtools/client/netmonitor/src/utils/request-utils.js
@@ -172,23 +172,35 @@ function getUrlHostName(url) {
  * @param {string} url - url string
  * @return {string} unicode host of a url
  */
 function getUrlHost(url) {
   return decodeUnicodeUrl((new URL(url)).host);
 }
 
 /**
+ * Helpers for getting the shceme portion of a url.
+ * For example helper returns "http" from http://domain.com/path/basename
+ *
+ * @param {string} url - url string
+ * @return {string} string scheme of a url
+ */
+function getUrlScheme(url) {
+  return (new URL(url)).protocol.replace(":", "").toLowerCase();
+}
+
+/**
  * Extract several details fields from a URL at once.
  */
 function getUrlDetails(url) {
   let baseNameWithQuery = getUrlBaseNameWithQuery(url);
   let host = getUrlHost(url);
   let hostname = getUrlHostName(url);
   let unicodeUrl = decodeUnicodeUrl(url);
+  let scheme = getUrlScheme(url);
 
   // Mark local hosts specially, where "local" is  as defined in the W3C
   // spec for secure contexts.
   // http://www.w3.org/TR/powerful-features/
   //
   //  * If the name falls under 'localhost'
   //  * If the name is an IPv4 address within 127.0.0.0/8
   //  * If the name is an IPv6 address within ::1/128
@@ -197,16 +209,17 @@ function getUrlDetails(url) {
   // been validated before it gets here.
   let isLocal = hostname.match(/(.+\.)?localhost$/) ||
                 hostname.match(/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}/) ||
                 hostname.match(/\[[0:]+1\]/);
 
   return {
     baseNameWithQuery,
     host,
+    scheme,
     unicodeUrl,
     isLocal
   };
 }
 
 /**
  * Parse a url's query string into its components
  *
@@ -291,18 +304,19 @@ function propertiesEqual(props, item1, i
 module.exports = {
   getFormDataSections,
   fetchHeaders,
   formDataURI,
   writeHeaderText,
   decodeUnicodeUrl,
   getAbbreviatedMimeType,
   getUrlBaseName,
-  getUrlQuery,
   getUrlBaseNameWithQuery,
+  getUrlDetails,
+  getUrlHost,
   getUrlHostName,
-  getUrlHost,
-  getUrlDetails,
+  getUrlQuery,
+  getUrlScheme,
   parseQueryString,
   parseFormData,
   propertiesEqual,
   ipToLong,
 };
--- a/devtools/client/netmonitor/src/utils/sort-predicates.js
+++ b/devtools/client/netmonitor/src/utils/sort-predicates.js
@@ -51,16 +51,21 @@ function file(first, second) {
   return result || waterfall(first, second);
 }
 
 function protocol(first, second) {
   const result = compareValues(first.httpVersion, second.httpVersion);
   return result || waterfall(first, second);
 }
 
+function scheme(first, second) {
+  const result = compareValues(first.urlDetails.scheme, second.urlDetails.scheme);
+  return result || waterfall(first, second);
+}
+
 function domain(first, second) {
   const firstDomain = first.urlDetails.host.toLowerCase();
   const secondDomain = second.urlDetails.host.toLowerCase();
   const result = compareValues(firstDomain, secondDomain);
   return result || waterfall(first, second);
 }
 
 function remoteip(first, second) {
@@ -114,16 +119,17 @@ function contentSize(first, second) {
   return result || waterfall(first, second);
 }
 
 exports.Sorters = {
   status,
   method,
   file,
   protocol,
+  scheme,
   cookies,
   setCookies,
   domain,
   remoteip,
   cause,
   type,
   transferred,
   contentSize,
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -15,18 +15,19 @@ Services.scriptloader.loadSubScript(
 
 const { EVENTS } = require("devtools/client/netmonitor/src/constants");
 const {
   getFormattedIPAndPort
 } = require("devtools/client/netmonitor/src/utils/format-utils");
 const {
   decodeUnicodeUrl,
   getUrlBaseName,
+  getUrlHost,
   getUrlQuery,
-  getUrlHost,
+  getUrlScheme,
 } = require("devtools/client/netmonitor/src/utils/request-utils");
 
 /* eslint-disable no-unused-vars, max-len */
 const EXAMPLE_URL = "http://example.com/browser/devtools/client/netmonitor/test/";
 const HTTPS_EXAMPLE_URL = "https://example.com/browser/devtools/client/netmonitor/test/";
 
 const API_CALLS_URL = EXAMPLE_URL + "html_api-calls-test-page.html";
 const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
@@ -375,16 +376,17 @@ function verifyRequestItemTarget(documen
   let { fuzzyUrl, status, statusText, cause, type, fullMimeType,
         transferred, size, time, displayedStatus } = data;
 
   let target = document.querySelectorAll(".request-list-item")[visibleIndex];
   let unicodeUrl = decodeUnicodeUrl(url);
   let name = getUrlBaseName(url);
   let query = getUrlQuery(url);
   let host = getUrlHost(url);
+  let scheme = getUrlScheme(url);
   let { httpVersion = "", remoteAddress, remotePort } = requestItem;
   let formattedIPPort = getFormattedIPAndPort(remoteAddress, remotePort);
   let remoteIP = remoteAddress ? `${formattedIPPort}` : "unknown";
 
   if (fuzzyUrl) {
     ok(requestItem.method.startsWith(method), "The attached method is correct.");
     ok(requestItem.url.startsWith(url), "The attached url is correct.");
   } else {
@@ -422,16 +424,22 @@ function verifyRequestItemTarget(documen
     domainTooltip, "The tooltip domain is correct.");
 
   is(target.querySelector(".requests-list-remoteip").textContent,
     remoteIP, "The displayed remote IP is correct.");
 
   is(target.querySelector(".requests-list-remoteip").getAttribute("title"),
     remoteIP, "The tooltip remote IP is correct.");
 
+  is(target.querySelector(".requests-list-scheme").textContent,
+    scheme, "The displayed scheme is correct.");
+
+  is(target.querySelector(".requests-list-scheme").getAttribute("title"),
+    scheme, "The tooltip scheme is correct.");
+
   if (status !== undefined) {
     let value = target.querySelector(".requests-list-status-icon")
                       .getAttribute("data-code");
     let codeValue = target.querySelector(".requests-list-status-code").textContent;
     let tooltip = target.querySelector(".requests-list-status").getAttribute("title");
     info("Displayed status: " + value);
     info("Displayed code: " + codeValue);
     info("Tooltip status: " + tooltip);
--- a/devtools/client/preferences/devtools.js
+++ b/devtools/client/preferences/devtools.js
@@ -145,17 +145,18 @@ pref("devtools.serviceWorkers.testing.en
 
 // Enable the Network Monitor
 pref("devtools.netmonitor.enabled", true);
 
 // The default Network Monitor UI settings
 pref("devtools.netmonitor.panes-network-details-width", 550);
 pref("devtools.netmonitor.panes-network-details-height", 450);
 pref("devtools.netmonitor.filters", "[\"all\"]");
-pref("devtools.netmonitor.hiddenColumns", "[\"cookies\",\"protocol\",\"remoteip\",\"setCookies\"]");
+pref("devtools.netmonitor.hiddenColumns",
+  "[\"cookies\",\"protocol\",\"remoteip\",\"scheme\",\"setCookies\"]");
 
 // The default Network monitor HAR export setting
 pref("devtools.netmonitor.har.defaultLogDir", "");
 pref("devtools.netmonitor.har.defaultFileName", "Archive %date");
 pref("devtools.netmonitor.har.jsonp", false);
 pref("devtools.netmonitor.har.jsonpCallback", "");
 pref("devtools.netmonitor.har.includeResponseBodies", true);
 pref("devtools.netmonitor.har.compress", false);