Bug 1356872 - Hard to distinguish IP from Port in IPv6 address. r?ntim draft
authorVangelis Katsikaros <vkatsikaros@gmail.com>
Mon, 17 Apr 2017 09:41:29 +0300
changeset 569264 757f67c42b4119f2fa64821d4fa17a3b3a7d9d73
parent 569138 0b77ed3f26c5335503bc16e85b8c067382e7bb1e
child 626153 3d2240ebf84cfda82f9e0ca5f314c445b2c4c5fb
push id56113
push uservkatsikaros@gmail.com
push dateThu, 27 Apr 2017 07:45:55 +0000
reviewersntim
bugs1356872
milestone55.0a1
Bug 1356872 - Hard to distinguish IP from Port in IPv6 address. r?ntim MozReview-Commit-ID: JqxWqaqZMI5
devtools/client/netmonitor/src/components/headers-panel.js
devtools/client/netmonitor/src/components/request-list-column-domain.js
devtools/client/netmonitor/src/components/request-list-column-remote-ip.js
devtools/client/netmonitor/src/utils/filter-text-utils.js
devtools/client/netmonitor/src/utils/format-utils.js
devtools/client/netmonitor/test/head.js
--- a/devtools/client/netmonitor/src/components/headers-panel.js
+++ b/devtools/client/netmonitor/src/components/headers-panel.js
@@ -6,17 +6,20 @@
 
 const {
   createClass,
   createFactory,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { NetMonitorController } = require("../netmonitor-controller");
-const { getFormattedSize } = require("../utils/format-utils");
+const {
+  getFormattedIPAndPort,
+  getFormattedSize,
+} = require("../utils/format-utils");
 const { L10N } = require("../utils/l10n");
 const {
   getHeadersURL,
   getHTTPStatusCodeURL,
 } = require("../utils/mdn-utils");
 const { writeHeaderText } = require("../utils/request-utils");
 
 // Components
@@ -157,17 +160,17 @@ const HeadersPanel = createClass({
     let summaryUrl = urlDetails.unicodeUrl ?
       this.renderSummary(SUMMARY_URL, urlDetails.unicodeUrl) : null;
 
     let summaryMethod = method ?
       this.renderSummary(SUMMARY_METHOD, method) : null;
 
     let summaryAddress = remoteAddress ?
       this.renderSummary(SUMMARY_ADDRESS,
-        remotePort ? `${remoteAddress}:${remotePort}` : remoteAddress) : null;
+        getFormattedIPAndPort(remoteAddress, remotePort)) : null;
 
     let summaryStatus;
 
     if (status) {
       let code;
       if (fromCache) {
         code = "cached";
       } else if (fromServiceWorker) {
--- a/devtools/client/netmonitor/src/components/request-list-column-domain.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-domain.js
@@ -4,16 +4,17 @@
 
 "use strict";
 
 const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
+const { getFormattedIPAndPort } = require("../utils/format-utils");
 const { L10N } = require("../utils/l10n");
 const { propertiesEqual } = require("../utils/request-utils");
 
 const { div } = DOM;
 
 const UPDATED_DOMAIN_PROPS = [
   "remoteAddress",
   "securityState",
@@ -29,20 +30,22 @@ const RequestListColumnDomain = createCl
   },
 
   shouldComponentUpdate(nextProps) {
     return !propertiesEqual(UPDATED_DOMAIN_PROPS, this.props.item, nextProps.item);
   },
 
   render() {
     let { item, onSecurityIconClick } = this.props;
-    let { remoteAddress, securityState, urlDetails: { host, isLocal } } = item;
+    let { remoteAddress, remotePort, securityState,
+      urlDetails: { host, isLocal } } = item;
     let iconClassList = ["requests-security-state-icon"];
     let iconTitle;
-    let title = host + (remoteAddress ? ` (${remoteAddress})` : "");
+    let title = host + (remoteAddress ?
+      ` (${getFormattedIPAndPort(remoteAddress, remotePort)})` : "");
 
     if (isLocal) {
       iconClassList.push("security-state-local");
       iconTitle = L10N.getStr("netmonitor.security.state.secure");
     } else if (securityState) {
       iconClassList.push(`security-state-${securityState}`);
       iconTitle = L10N.getStr(`netmonitor.security.state.${securityState}`);
     }
--- a/devtools/client/netmonitor/src/components/request-list-column-remote-ip.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-remote-ip.js
@@ -4,33 +4,35 @@
 
 "use strict";
 
 const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
+const { getFormattedIPAndPort } = require("../utils/format-utils");
 
 const { div } = DOM;
 
 const RequestListColumnRemoteIP = createClass({
   displayName: "RequestListColumnRemoteIP",
 
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return this.props.item.remoteAddress !== nextProps.item.remoteAddress;
   },
 
   render() {
     let { remoteAddress, remotePort } = this.props.item;
-    let remoteIP = remoteAddress ? `${remoteAddress}:${remotePort}` : "unknown";
+    let remoteIP = remoteAddress ?
+      getFormattedIPAndPort(remoteAddress, remotePort) : "unknown";
 
     return (
       div({ className: "requests-list-column requests-list-remoteip", title: remoteIP },
         remoteIP
       )
     );
   }
 });
--- a/devtools/client/netmonitor/src/utils/filter-text-utils.js
+++ b/devtools/client/netmonitor/src/utils/filter-text-utils.js
@@ -26,16 +26,17 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 "use strict";
 
 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",
   "mime-type",
@@ -127,17 +128,18 @@ function isFlagFilterMatch(item, { type,
       let protocol = item.httpVersion;
       match = typeof protocol === "string" ?
                 protocol.toLowerCase().includes(value) : false;
       break;
     case "domain":
       match = item.urlDetails.host.toLowerCase().includes(value);
       break;
     case "remote-ip":
-      match = `${item.remoteAddress}:${item.remotePort}`.toLowerCase().includes(value);
+      match = getFormattedIPAndPort(item.remoteAddress, item.remotePort)
+        .toLowerCase().includes(value);
       break;
     case "has-response-header":
       if (typeof item.responseHeaders === "object") {
         let { headers } = item.responseHeaders;
         match = headers.findIndex(h => h.name.toLowerCase() === value) > -1;
       } else {
         match = false;
       }
--- a/devtools/client/netmonitor/src/utils/format-utils.js
+++ b/devtools/client/netmonitor/src/utils/format-utils.js
@@ -72,14 +72,29 @@ function getFormattedTime(ms) {
   if (ms < MAX_SECOND) {
     const sec = ms / MAX_MILLISECOND;
     return L10N.getFormatStr("networkMenu.second", getTimeWithDecimals(sec));
   }
   const min = ms / MAX_SECOND;
   return L10N.getFormatStr("networkMenu.minute", getTimeWithDecimals(min));
 }
 
+/**
+ * Formats IP (v4 and v6) and port
+ *
+ * @param {string} ip - IP address
+ * @param {string} port
+ * @return {string} the formatted IP + port
+ */
+function getFormattedIPAndPort(ip, port) {
+  if (!port) {
+    return ip;
+  }
+  return ip.match(/:+/) ? `[${ip}]:${port}` : `${ip}:${port}`;
+}
+
 module.exports = {
+  getFormattedIPAndPort,
   getFormattedSize,
   getFormattedTime,
   getSizeWithDecimals,
   getTimeWithDecimals,
 };
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -10,16 +10,19 @@
 
 // shared-head.js handles imports, constants, and utility functions
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
 
 const { EVENTS } = require("devtools/client/netmonitor/src/constants");
 const {
+  getFormattedIPAndPort
+} = require("devtools/client/netmonitor/src/utils/format-utils");
+const {
   decodeUnicodeUrl,
   getUrlBaseName,
   getUrlQuery,
   getUrlHost,
 } = 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/";
@@ -371,19 +374,20 @@ 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 hostPort = getUrlHost(url);
+  let host = getUrlHost(url);
   let { httpVersion = "", remoteAddress, remotePort } = requestItem;
-  let remoteIP = remoteAddress ? `${remoteAddress}:${remotePort}` : "unknown";
+  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 {
     is(requestItem.method, method, "The attached method is correct.");
     is(requestItem.url, url, "The attached url is correct.");
   }
@@ -406,19 +410,19 @@ function verifyRequestItemTarget(documen
 
   is(target.querySelector(".requests-list-protocol").textContent,
     httpVersion, "The displayed protocol is correct.");
 
   is(target.querySelector(".requests-list-protocol").getAttribute("title"),
     httpVersion, "The tooltip protocol is correct.");
 
   is(target.querySelector(".requests-list-domain").textContent,
-    hostPort, "The displayed domain is correct.");
+    host, "The displayed domain is correct.");
 
-  let domainTooltip = hostPort + (remoteAddress ? " (" + remoteAddress + ")" : "");
+  let domainTooltip = host + (remoteAddress ? " (" + formattedIPPort + ")" : "");
   is(target.querySelector(".requests-list-domain").getAttribute("title"),
     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.");