Bug 1308507 - Remove all usages of nsIURL and NetworkHelper r?jsnajdr draft
authorRicky Chien <ricky060709@gmail.com>
Fri, 04 Nov 2016 17:49:19 +0800
changeset 439735 77abc85dffcba27c8bad7f7511914c6bde58ca71
parent 439734 51750761f2c61c64cf0553f6cb5fefd4999d3bc0
child 537236 a5b339d8c49e4d43dd6f39d9431f6bbedd4ca808
push id36076
push userbmo:rchien@mozilla.com
push dateWed, 16 Nov 2016 15:11:25 +0000
reviewersjsnajdr
bugs1308507
milestone53.0a1
Bug 1308507 - Remove all usages of nsIURL and NetworkHelper r?jsnajdr MozReview-Commit-ID: Gu1kE0oHDRP
devtools/client/netmonitor/custom-request-view.js
devtools/client/netmonitor/har/har-builder.js
devtools/client/netmonitor/netmonitor-controller.js
devtools/client/netmonitor/netmonitor-view.js
devtools/client/netmonitor/request-list-context-menu.js
devtools/client/netmonitor/request-utils.js
devtools/client/netmonitor/requests-menu-view.js
devtools/client/netmonitor/sort-predicates.js
devtools/client/netmonitor/test/head.js
--- a/devtools/client/netmonitor/custom-request-view.js
+++ b/devtools/client/netmonitor/custom-request-view.js
@@ -1,19 +1,21 @@
 /* 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/. */
 /* globals window, dumpn, gNetwork, $, EVENTS, NetMonitorView */
 "use strict";
 
-const {Task} = require("devtools/shared/task");
-const {writeHeaderText, getKeyWithEvent} = require("./request-utils");
-
-loader.lazyRequireGetter(this, "NetworkHelper",
-  "devtools/shared/webconsole/network-helper");
+const { Task } = require("devtools/shared/task");
+const {
+  writeHeaderText,
+  getKeyWithEvent,
+  getUrlQuery,
+  parseQueryString,
+} = require("./request-utils");
 
 /**
  * Functions handling the custom request view.
  */
 function CustomRequestView() {
   dumpn("CustomRequestView was instantiated");
 }
 
@@ -107,18 +109,17 @@ CustomRequestView.prototype = {
 
   /**
    * Update the query string field based on the url.
    *
    * @param object url
    *        The URL to extract query string from.
    */
   updateCustomQuery: function (url) {
-    let paramsArray = NetworkHelper.parseQueryString(
-      NetworkHelper.nsIURL(url).query);
+    const paramsArray = parseQueryString(getUrlQuery(url));
 
     if (!paramsArray) {
       $("#custom-query").hidden = true;
       return;
     }
 
     $("#custom-query").hidden = false;
     $("#custom-query-value").value = writeQueryText(paramsArray);
@@ -130,17 +131,17 @@ CustomRequestView.prototype = {
    * @param object queryText
    *        The contents of the query string field.
    */
   updateCustomUrl: function (queryText) {
     let params = parseQueryText(queryText);
     let queryString = writeQueryString(params);
 
     let url = $("#custom-url-value").value;
-    let oldQuery = NetworkHelper.nsIURL(url).query;
+    let oldQuery = getUrlQuery(url);
     let path = url.replace(oldQuery, queryString);
 
     $("#custom-url-value").value = path;
   }
 };
 
 /**
  * Parse text representation of multiple HTTP headers.
--- a/devtools/client/netmonitor/har/har-builder.js
+++ b/devtools/client/netmonitor/har/har-builder.js
@@ -3,19 +3,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { defer, all } = require("promise");
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const Services = require("Services");
 const appInfo = Services.appinfo;
 const { CurlUtils } = require("devtools/client/shared/curl");
-const { getFormDataSections } = require("devtools/client/netmonitor/request-utils");
-
-loader.lazyRequireGetter(this, "NetworkHelper", "devtools/shared/webconsole/network-helper");
+const {
+  getFormDataSections,
+  getUrlQuery,
+  parseQueryString,
+} = require("devtools/client/netmonitor/request-utils");
 
 loader.lazyGetter(this, "L10N", () => {
   return new LocalizationHelper("devtools/client/locales/har.properties");
 });
 
 const HAR_VERSION = "1.1";
 
 /**
@@ -165,18 +167,17 @@ HarBuilder.prototype = {
     request.method = file.method;
     request.url = file.url;
     request.httpVersion = file.httpVersion || "";
 
     request.headers = this.buildHeaders(file.requestHeaders);
     request.headers = this.appendHeadersPostData(request.headers, file);
     request.cookies = this.buildCookies(file.requestCookies);
 
-    request.queryString = NetworkHelper.parseQueryString(
-      NetworkHelper.nsIURL(file.url).query) || [];
+    request.queryString = parseQueryString(getUrlQuery(file.url)) || [];
 
     request.postData = this.buildPostData(file);
 
     request.headersSize = file.requestHeaders.headersSize;
 
     // Set request body size, but make sure the body is fetched
     // from the backend.
     if (file.requestPostData) {
@@ -275,17 +276,17 @@ HarBuilder.prototype = {
         // Extract form parameters and produce nice HAR array.
         getFormDataSections(
           file.requestHeaders,
           file.requestHeadersFromUploadStream,
           file.requestPostData,
           this._options.getString
         ).then(formDataSections => {
           formDataSections.forEach(section => {
-            let paramsArray = NetworkHelper.parseQueryString(section);
+            let paramsArray = parseQueryString(section);
             if (paramsArray) {
               postData.params = [...postData.params, ...paramsArray];
             }
           });
         });
       }
     });
 
--- a/devtools/client/netmonitor/netmonitor-controller.js
+++ b/devtools/client/netmonitor/netmonitor-controller.js
@@ -51,24 +51,16 @@ XPCOMUtils.defineConstant(this, "Editor"
 XPCOMUtils.defineConstant(this, "Prefs", Prefs);
 
 XPCOMUtils.defineLazyModuleGetter(this, "Chart",
   "resource://devtools/client/shared/widgets/Chart.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
   "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
 
-Object.defineProperty(this, "NetworkHelper", {
-  get: function () {
-    return require("devtools/shared/webconsole/network-helper");
-  },
-  configurable: true,
-  enumerable: true
-});
-
 /**
  * Object defining the network monitor controller components.
  */
 var NetMonitorController = {
   /**
    * Initializes the view and connects the monitor client.
    *
    * @return object
--- a/devtools/client/netmonitor/netmonitor-view.js
+++ b/devtools/client/netmonitor/netmonitor-view.js
@@ -3,31 +3,33 @@
 /* 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/. */
 /* import-globals-from ./netmonitor-controller.js */
 /* globals Prefs, gNetwork, setInterval, setTimeout, clearInterval, clearTimeout, btoa */
 /* exported $, $all */
 "use strict";
 
-XPCOMUtils.defineLazyGetter(this, "NetworkHelper", function () {
-  return require("devtools/shared/webconsole/network-helper");
-});
-
 /* eslint-disable mozilla/reject-some-requires */
 const {VariablesView} = require("resource://devtools/client/shared/widgets/VariablesView.jsm");
 /* eslint-disable mozilla/reject-some-requires */
 const {VariablesViewController} = require("resource://devtools/client/shared/widgets/VariablesViewController.jsm");
 const {ToolSidebar} = require("devtools/client/framework/sidebar");
 const {testing: isTesting} = require("devtools/shared/flags");
 const {ViewHelpers, Heritage} = require("devtools/client/shared/widgets/view-helpers");
 const {Filters} = require("./filter-predicates");
-const {getFormDataSections,
-       formDataURI,
-       getUriHostPort} = require("./request-utils");
+const {
+  formDataURI,
+  decodeUnicodeUrl,
+  getFormDataSections,
+  getUrlBaseName,
+  getUrlQuery,
+  getUrlHost,
+  parseQueryString,
+} = require("./request-utils");
 const {L10N} = require("./l10n");
 const {RequestsMenuView} = require("./requests-menu-view");
 const {CustomRequestView} = require("./custom-request-view");
 const {ToolbarView} = require("./toolbar-view");
 const {configureStore} = require("./store");
 const {PerformanceStatisticsView} = require("./performance-statistics-view");
 
 // Initialize the global redux variables
@@ -547,17 +549,17 @@ NetworkDetailsView.prototype = {
   /**
    * Sets the network request summary shown in this view.
    *
    * @param object data
    *        The data source (this should be the attachment of a request item).
    */
   _setSummary: function (data) {
     if (data.url) {
-      let unicodeUrl = NetworkHelper.convertToUnicode(unescape(data.url));
+      let unicodeUrl = decodeUnicodeUrl(data.url);
       $("#headers-summary-url-value").setAttribute("value", unicodeUrl);
       $("#headers-summary-url-value").setAttribute("tooltiptext", unicodeUrl);
       $("#headers-summary-url").removeAttribute("hidden");
     } else {
       $("#headers-summary-url").setAttribute("hidden", "true");
     }
 
     if (data.method) {
@@ -738,17 +740,17 @@ NetworkDetailsView.prototype = {
 
   /**
    * Sets the network request get params shown in this view.
    *
    * @param string url
    *        The request's url.
    */
   _setRequestGetParams: function (url) {
-    let query = NetworkHelper.nsIURL(url).query;
+    let query = getUrlQuery(url);
     if (query) {
       this._addParams(this._paramsQueryString, query);
     }
   },
 
   /**
    * Sets the network request post params shown in this view.
    *
@@ -820,17 +822,17 @@ NetworkDetailsView.prototype = {
    * Populates the params container in this view with the specified data.
    *
    * @param string name
    *        The type of params to populate (get or post).
    * @param string queryString
    *        A query string of params (e.g. "?foo=bar&baz=42").
    */
   _addParams: function (name, queryString) {
-    let paramsArray = NetworkHelper.parseQueryString(queryString);
+    let paramsArray = parseQueryString(queryString);
     if (!paramsArray) {
       return;
     }
     let paramsScope = this._params.addScope(name);
     paramsScope.expanded = true;
 
     for (let param of paramsArray) {
       let paramVar = paramsScope.addItem(param.name, {}, {relaxed: true});
@@ -913,17 +915,17 @@ NetworkDetailsView.prototype = {
       $("#response-content-image-box").setAttribute("align", "center");
       $("#response-content-image-box").setAttribute("pack", "center");
       $("#response-content-image-box").hidden = false;
       $("#response-content-image").src = formDataURI(mimeType, encoding, responseBody);
 
       // Immediately display additional information about the image:
       // file name, mime type and encoding.
       $("#response-content-image-name-value").setAttribute("value",
-        NetworkHelper.nsIURL(url).fileName);
+        getUrlBaseName(url));
       $("#response-content-image-mime-value").setAttribute("value", mimeType);
 
       // Wait for the image to load in order to display the width and height.
       $("#response-content-image").onload = e => {
         // XUL images are majestic so they don't bother storing their dimensions
         // in width and height attributes like the rest of the folk. Hack around
         // this by getting the bounding client rect and subtracting the margins.
         let { width, height } = e.target.getBoundingClientRect();
@@ -1121,17 +1123,17 @@ NetworkDetailsView.prototype = {
       let disabledLabel = L10N.getStr("netmonitor.security.disabled");
 
       // Connection parameters
       setValue("#security-protocol-version-value",
         securityInfo.protocolVersion);
       setValue("#security-ciphersuite-value", securityInfo.cipherSuite);
 
       // Host header
-      let domain = getUriHostPort(url);
+      let domain = getUrlHost(url);
       let hostHeader = L10N.getFormatStr("netmonitor.security.hostHeader",
         domain);
       setValue("#security-info-host-header", hostHeader);
 
       // Parameters related to the domain
       setValue("#security-http-strict-transport-security-value",
                 securityInfo.hsts ? enabledLabel : disabledLabel);
 
--- a/devtools/client/netmonitor/request-list-context-menu.js
+++ b/devtools/client/netmonitor/request-list-context-menu.js
@@ -8,27 +8,29 @@
 
 const Services = require("Services");
 const { Task } = require("devtools/shared/task");
 const { Curl } = require("devtools/client/shared/curl");
 const { gDevTools } = require("devtools/client/framework/devtools");
 const Menu = require("devtools/client/framework/menu");
 const MenuItem = require("devtools/client/framework/menu-item");
 const { L10N } = require("./l10n");
-const { formDataURI, getFormDataSections } = require("./request-utils");
+const {
+  formDataURI,
+  getFormDataSections,
+  getUrlQuery,
+  parseQueryString,
+} = require("./request-utils");
 
 loader.lazyRequireGetter(this, "HarExporter",
   "devtools/client/netmonitor/har/har-exporter", true);
 
 loader.lazyServiceGetter(this, "clipboardHelper",
   "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
 
-loader.lazyRequireGetter(this, "NetworkHelper",
-  "devtools/shared/webconsole/network-helper");
-
 function RequestListContextMenu() {}
 
 RequestListContextMenu.prototype = {
   get selectedItem() {
     return NetMonitorView.RequestsMenu.selectedItem;
   },
 
   get items() {
@@ -51,18 +53,17 @@ RequestListContextMenu.prototype = {
       visible: !!selectedItem,
       click: () => this.copyUrl(),
     }));
 
     menu.append(new MenuItem({
       id: "request-menu-context-copy-url-params",
       label: L10N.getStr("netmonitor.context.copyUrlParams"),
       accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"),
-      visible: !!(selectedItem &&
-               NetworkHelper.nsIURL(selectedItem.attachment.url).query),
+      visible: !!(selectedItem && getUrlQuery(selectedItem.attachment.url)),
       click: () => this.copyUrlParams(),
     }));
 
     menu.append(new MenuItem({
       id: "request-menu-context-copy-post-data",
       label: L10N.getStr("netmonitor.context.copyPostData"),
       accesskey: L10N.getStr("netmonitor.context.copyPostData.accesskey"),
       visible: !!(selectedItem && selectedItem.attachment.requestPostData),
@@ -198,17 +199,17 @@ RequestListContextMenu.prototype = {
   },
 
   /**
    * Copy the request url query string parameters from the currently
    * selected item.
    */
   copyUrlParams() {
     let { url } = this.selectedItem.attachment;
-    let params = NetworkHelper.nsIURL(url).query.split("&");
+    let params = getUrlQuery(url).split("&");
     let string = params.join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n");
     clipboardHelper.copyString(string);
   },
 
   /**
    * Copy the request form data parameters (or raw payload) from
    * the currently selected item.
    */
@@ -219,17 +220,17 @@ RequestListContextMenu.prototype = {
     let formDataSections = yield getFormDataSections(
       selected.requestHeaders,
       selected.requestHeadersFromUploadStream,
       selected.requestPostData,
       gNetwork.getString.bind(gNetwork));
 
     let params = [];
     formDataSections.forEach(section => {
-      let paramsArray = NetworkHelper.parseQueryString(section);
+      let paramsArray = parseQueryString(section);
       if (paramsArray) {
         params = [...params, ...paramsArray];
       }
     });
 
     let string = params
       .map(param => param.name + (param.value ? "=" + param.value : ""))
       .join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n");
--- a/devtools/client/netmonitor/request-utils.js
+++ b/devtools/client/netmonitor/request-utils.js
@@ -1,59 +1,52 @@
 "use strict";
+
 /* eslint-disable mozilla/reject-some-requires */
 const { Ci } = require("chrome");
 const { KeyCodes } = require("devtools/client/shared/keycodes");
 const { Task } = require("devtools/shared/task");
-const NetworkHelper = require("devtools/shared/webconsole/network-helper");
 
 /**
  * Helper method to get a wrapped function which can be bound to as
  * an event listener directly and is executed only when data-key is
  * present in event.target.
  *
- * @param function callback
- *          Function to execute execute when data-key
- *          is present in event.target.
- * @param bool onlySpaceOrReturn
- *          Flag to indicate if callback should only be called
-            when the space or return button is pressed
- * @return function
- *          Wrapped function with the target data-key as the first argument
- *          and the event as the second argument.
+ * @param {function} callback - function to execute execute when data-key
+ *                              is present in event.target.
+ * @param {bool} onlySpaceOrReturn - flag to indicate if callback should only
+ *                                   be called when the space or return button
+ *                                   is pressed
+ * @return {function} wrapped function with the target data-key as the first argument
+ *                    and the event as the second argument.
  */
-exports.getKeyWithEvent = function (callback, onlySpaceOrReturn) {
+function getKeyWithEvent(callback, onlySpaceOrReturn) {
   return function (event) {
     let key = event.target.getAttribute("data-key");
     let filterKeyboardEvent = !onlySpaceOrReturn ||
                               event.keyCode === KeyCodes.DOM_VK_SPACE ||
                               event.keyCode === KeyCodes.DOM_VK_RETURN;
 
     if (key && filterKeyboardEvent) {
       callback.call(null, key);
     }
   };
-};
+}
 
 /**
  * Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
  * POST request.
  *
- * @param object headers
- *        The "requestHeaders".
- * @param object uploadHeaders
- *        The "requestHeadersFromUploadStream".
- * @param object postData
- *        The "requestPostData".
- * @param object getString
-          Callback to retrieve a string from a LongStringGrip.
- * @return array
- *        A promise that is resolved with the extracted form data.
+ * @param {object} headers - the "requestHeaders".
+ * @param {object} uploadHeaders - the "requestHeadersFromUploadStream".
+ * @param {object} postData - the "requestPostData".
+ * @param {function} getString - callback to retrieve a string from a LongStringGrip.
+ * @return {array} a promise list that is resolved with the extracted form data.
  */
-exports.getFormDataSections = Task.async(function* (headers, uploadHeaders, postData,
+const getFormDataSections = Task.async(function* (headers, uploadHeaders, postData,
                                                     getString) {
   let formDataSections = [];
 
   let { headers: requestHeaders } = headers;
   let { headers: payloadHeaders } = uploadHeaders;
   let allHeaders = [...payloadHeaders, ...requestHeaders];
 
   let contentTypeHeader = allHeaders.find(e => {
@@ -78,83 +71,142 @@ exports.getFormDataSections = Task.async
   }
 
   return formDataSections;
 });
 
 /**
  * Form a data: URI given a mime type, encoding, and some text.
  *
- * @param {String} mimeType the mime type
- * @param {String} encoding the encoding to use; if not set, the
- *        text will be base64-encoded.
- * @param {String} text the text of the URI.
- * @return {String} a data: URI
+ * @param {string} mimeType - mime type
+ * @param {string} encoding - encoding to use; if not set, the
+ *                            text will be base64-encoded.
+ * @param {string} text - text of the URI.
+ * @return {string} a data URI
  */
-exports.formDataURI = function (mimeType, encoding, text) {
+function formDataURI(mimeType, encoding, text) {
   if (!encoding) {
     encoding = "base64";
     text = btoa(text);
   }
   return "data:" + mimeType + ";" + encoding + "," + text;
-};
+}
 
 /**
  * Write out a list of headers into a chunk of text
  *
- * @param array headers
- *        Array of headers info {name, value}
- * @return string text
- *         List of headers in text format
+ * @param {array} headers - array of headers info { name, value }
+ * @return {string} list of headers in text format
  */
-exports.writeHeaderText = function (headers) {
+function writeHeaderText(headers) {
   return headers.map(({name, value}) => name + ": " + value).join("\n");
-};
+}
+
+/**
+ * Convert a string into unicode if string is valid.
+ * If there is a malformed URI sequence, it returns input string.
+ *
+ * @param {string} url - a string
+ * @return {string} unicode string
+ */
+function decodeUnicodeUrl(string) {
+  try {
+    return decodeURIComponent(string);
+  } catch (err) {
+    // Ignore error and return input string directly.
+  }
+  return string;
+}
 
 /**
  * Helper for getting an abbreviated string for a mime type.
  *
- * @param string mimeType
- * @return string
+ * @param {string} mimeType - mime type
+ * @return {string} abbreviated mime type
  */
-exports.getAbbreviatedMimeType = function (mimeType) {
+function getAbbreviatedMimeType(mimeType) {
   if (!mimeType) {
     return "";
   }
   return (mimeType.split(";")[0].split("/")[1] || "").split("+")[0];
-};
+}
+
+/**
+ * Helpers for getting the last portion of a url.
+ * For example helper returns "basename" from http://domain.com/path/basename
+ * If basename portion is empty, it returns the url pathname.
+ *
+ * @param {string} url - url string
+ * @return {string} unicode basename of a url
+ */
+function getUrlBaseName(url) {
+  const pathname = (new URL(url)).pathname;
+  return decodeUnicodeUrl(
+    pathname.replace(/\S*\//, "") || pathname || "/");
+}
+
+/**
+ * Helpers for getting the query portion of a url.
+ *
+ * @param {string} url - url string
+ * @return {string} unicode query of a url
+ */
+function getUrlQuery(url) {
+  return decodeUnicodeUrl((new URL(url)).search.replace(/^\?/, ""));
+}
 
 /**
- * Helpers for getting details about an nsIURL.
+ * Helpers for getting unicode name and query portions of a url.
+ *
+ * @param {string} url - url string
+ * @return {string} unicode basename and query portions of a url
+ */
+function getUrlBaseNameWithQuery(url) {
+  return getUrlBaseName(url) + decodeUnicodeUrl((new URL(url)).search);
+}
+
+/**
+ * Helpers for getting unicode hostname portion of an URL.
  *
- * @param nsIURL | string url
- * @return string
+ * @param {string} url - url string
+ * @return {string} unicode hostname of a url
+ */
+function getUrlHostName(url) {
+  return decodeUnicodeUrl((new URL(url)).hostname);
+}
+
+/**
+ * Helpers for getting unicode host portion of an URL.
+ *
+ * @param {string} url - url string
+ * @return {string} unicode host of a url
  */
-exports.getUriNameWithQuery = function (url) {
-  if (!(url instanceof Ci.nsIURL)) {
-    url = NetworkHelper.nsIURL(url);
+function getUrlHost(url) {
+  return decodeUnicodeUrl((new URL(url)).host);
+}
+
+/**
+ * Parse a url's query string into its components
+ *
+ * @param {string} query - query string of a url portion
+ * @return {array} array of query params { name, value }
+ */
+function parseQueryString(query) {
+  if (!query) {
+    return null;
   }
 
-  let name = NetworkHelper.convertToUnicode(
-    unescape(url.fileName || url.filePath || "/"));
-  let query = NetworkHelper.convertToUnicode(unescape(url.query));
-
-  return name + (query ? "?" + query : "");
-};
-
-exports.getUriHostPort = function (url) {
-  if (!(url instanceof Ci.nsIURL)) {
-    url = NetworkHelper.nsIURL(url);
-  }
-  return NetworkHelper.convertToUnicode(unescape(url.hostPort));
-};
-
-exports.getUriHost = function (url) {
-  return exports.getUriHostPort(url).replace(/:\d+$/, "");
-};
+  return query.replace(/^[?&]/, "").split("&").map(e => {
+    let param = e.split("=");
+    return {
+      name: param[0] ? decodeUnicodeUrl(param[0]) : "",
+      value: param[1] ? decodeUnicodeUrl(param[1]) : "",
+    };
+  });
+}
 
 /**
  * Convert a nsIContentPolicy constant to a display string
  */
 const LOAD_CAUSE_STRINGS = {
   [Ci.nsIContentPolicy.TYPE_INVALID]: "invalid",
   [Ci.nsIContentPolicy.TYPE_OTHER]: "other",
   [Ci.nsIContentPolicy.TYPE_SCRIPT]: "script",
@@ -175,11 +227,27 @@ const LOAD_CAUSE_STRINGS = {
   [Ci.nsIContentPolicy.TYPE_CSP_REPORT]: "csp",
   [Ci.nsIContentPolicy.TYPE_XSLT]: "xslt",
   [Ci.nsIContentPolicy.TYPE_BEACON]: "beacon",
   [Ci.nsIContentPolicy.TYPE_FETCH]: "fetch",
   [Ci.nsIContentPolicy.TYPE_IMAGESET]: "imageset",
   [Ci.nsIContentPolicy.TYPE_WEB_MANIFEST]: "webManifest"
 };
 
-exports.loadCauseString = function (causeType) {
+function loadCauseString(causeType) {
   return LOAD_CAUSE_STRINGS[causeType] || "unknown";
+}
+
+module.exports = {
+  getKeyWithEvent,
+  getFormDataSections,
+  formDataURI,
+  writeHeaderText,
+  decodeUnicodeUrl,
+  getAbbreviatedMimeType,
+  getUrlBaseName,
+  getUrlQuery,
+  getUrlBaseNameWithQuery,
+  getUrlHostName,
+  getUrlHost,
+  parseQueryString,
+  loadCauseString,
 };
--- a/devtools/client/netmonitor/requests-menu-view.js
+++ b/devtools/client/netmonitor/requests-menu-view.js
@@ -19,28 +19,26 @@ const {setImageTooltip, getImageDimensio
 const {Heritage, WidgetMethods, setNamedTimeout} =
   require("devtools/client/shared/widgets/view-helpers");
 const {CurlUtils} = require("devtools/client/shared/curl");
 const {Filters, isFreetextMatch} = require("./filter-predicates");
 const {Sorters} = require("./sort-predicates");
 const {L10N, WEBCONSOLE_L10N} = require("./l10n");
 const {formDataURI,
        writeHeaderText,
+       decodeUnicodeUrl,
        getKeyWithEvent,
        getAbbreviatedMimeType,
-       getUriNameWithQuery,
-       getUriHostPort,
-       getUriHost,
+       getUrlBaseNameWithQuery,
+       getUrlHost,
+       getUrlHostName,
        loadCauseString} = require("./request-utils");
 const Actions = require("./actions/index");
 const RequestListContextMenu = require("./request-list-context-menu");
 
-loader.lazyRequireGetter(this, "NetworkHelper",
-  "devtools/shared/webconsole/network-helper");
-
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const EPSILON = 0.001;
 // ms
 const RESIZE_REFRESH_RATE = 50;
 // ms
 const REQUESTS_REFRESH_RATE = 50;
 // tooltip show/hide delay in ms
 const REQUESTS_TOOLTIP_TOGGLE_DELAY = 500;
@@ -920,27 +918,20 @@ RequestsMenuView.prototype = Heritage.ex
 
     switch (key) {
       case "method": {
         let node = $(".requests-menu-method", target);
         node.setAttribute("value", value);
         break;
       }
       case "url": {
-        let uri;
-        try {
-          uri = NetworkHelper.nsIURL(value);
-        } catch (e) {
-          // User input may not make a well-formed url yet.
-          break;
-        }
-        let nameWithQuery = getUriNameWithQuery(uri);
-        let hostPort = getUriHostPort(uri);
-        let host = getUriHost(uri);
-        let unicodeUrl = NetworkHelper.convertToUnicode(unescape(uri.spec));
+        let nameWithQuery = getUrlBaseNameWithQuery(value);
+        let hostPort = getUrlHost(value);
+        let host = getUrlHostName(value);
+        let unicodeUrl = decodeUnicodeUrl(value);
 
         let file = $(".requests-menu-file", target);
         file.setAttribute("value", nameWithQuery);
         file.setAttribute("tooltiptext", unicodeUrl);
 
         let domain = $(".requests-menu-domain", target);
         domain.setAttribute("value", hostPort);
         domain.setAttribute("tooltiptext", hostPort);
--- a/devtools/client/netmonitor/sort-predicates.js
+++ b/devtools/client/netmonitor/sort-predicates.js
@@ -1,13 +1,13 @@
 "use strict";
 
 const { getAbbreviatedMimeType,
-        getUriNameWithQuery,
-        getUriHostPort,
+        getUrlBaseNameWithQuery,
+        getUrlHost,
         loadCauseString } = require("./request-utils");
 
 /**
  * Predicates used when sorting items.
  *
  * @param object first
  *        The first item used in the comparison.
  * @param object second
@@ -31,27 +31,27 @@ function status(first, second) {
 function method(first, second) {
   if (first.method == second.method) {
     return first.startedMillis - second.startedMillis;
   }
   return first.method > second.method ? 1 : -1;
 }
 
 function file(first, second) {
-  let firstUrl = getUriNameWithQuery(first.url).toLowerCase();
-  let secondUrl = getUriNameWithQuery(second.url).toLowerCase();
+  let firstUrl = getUrlBaseNameWithQuery(first.url).toLowerCase();
+  let secondUrl = getUrlBaseNameWithQuery(second.url).toLowerCase();
   if (firstUrl == secondUrl) {
     return first.startedMillis - second.startedMillis;
   }
   return firstUrl > secondUrl ? 1 : -1;
 }
 
 function domain(first, second) {
-  let firstDomain = getUriHostPort(first.url).toLowerCase();
-  let secondDomain = getUriHostPort(second.url).toLowerCase();
+  let firstDomain = getUrlHost(first.url).toLowerCase();
+  let secondDomain = getUrlHost(second.url).toLowerCase();
   if (firstDomain == secondDomain) {
     return first.startedMillis - second.startedMillis;
   }
   return firstDomain > secondDomain ? 1 : -1;
 }
 
 function cause(first, second) {
   let firstCause = loadCauseString(first.cause.type);
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -4,18 +4,23 @@
 
 /* import-globals-from ../../framework/test/shared-head.js */
 
 // shared-head.js handles imports, constants, and utility functions
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
 
-var NetworkHelper = require("devtools/shared/webconsole/network-helper");
 var { Toolbox } = require("devtools/client/framework/toolbox");
+const {
+  decodeUnicodeUrl,
+  getUrlBaseName,
+  getUrlQuery,
+  getUrlHost,
+} = require("devtools/client/netmonitor/request-utils");
 
 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";
 const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
 const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
@@ -257,21 +262,20 @@ function verifyRequestItemTarget(aReques
 
   info("Widget index of item: " + widgetIndex);
   info("Visible index of item: " + visibleIndex);
 
   let { fuzzyUrl, status, statusText, cause, type, fullMimeType,
         transferred, size, time, displayedStatus } = aData;
   let { attachment, target } = aRequestItem;
 
-  let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
-  let unicodeUrl = NetworkHelper.convertToUnicode(unescape(aUrl));
-  let name = NetworkHelper.convertToUnicode(unescape(uri.fileName || uri.filePath || "/"));
-  let query = NetworkHelper.convertToUnicode(unescape(uri.query));
-  let hostPort = uri.hostPort;
+  let unicodeUrl = decodeUnicodeUrl(aUrl);
+  let name = getUrlBaseName(aUrl);
+  let query = getUrlQuery(aUrl);
+  let hostPort = getUrlHost(aUrl);
   let remoteAddress = attachment.remoteAddress;
 
   if (fuzzyUrl) {
     ok(attachment.method.startsWith(aMethod), "The attached method is correct.");
     ok(attachment.url.startsWith(aUrl), "The attached url is correct.");
   } else {
     is(attachment.method, aMethod, "The attached method is correct.");
     is(attachment.url, aUrl, "The attached url is correct.");