Bug 1500915 - Properly decode urls. r=Honza
authorMrigank Krishan <mrigankkrishan@gmail.com>
Wed, 15 May 2019 08:47:51 +0000
changeset 473910 11ea9feda2a39cd013315ed5afcb5e8abbdd099f
parent 473909 3b3fc85fd247f3beb4a446a3b80da22e3cf0e703
child 473911 21897fb59491b16f2c611c70a9d5d5ddc3741115
push id113116
push userrgurzau@mozilla.com
push dateWed, 15 May 2019 16:03:00 +0000
treeherdermozilla-inbound@fd32e1c1f0ed [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersHonza
bugs1500915
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1500915 - Properly decode urls. r=Honza Used decodeURI insted of decodeURLComponent and replace `+` with ` `(space). I've not tackled the line break issue yet. Differential Revision: https://phabricator.services.mozilla.com/D23014
devtools/client/netmonitor/src/utils/request-utils.js
devtools/client/netmonitor/test/browser.ini
devtools/client/netmonitor/test/browser_net_decode-params.js
devtools/client/netmonitor/test/browser_net_decode-url.js
devtools/client/netmonitor/test/head.js
devtools/client/netmonitor/test/html_header-test-page.html
devtools/client/shared/unicode-url.js
--- a/devtools/client/netmonitor/src/utils/request-utils.js
+++ b/devtools/client/netmonitor/src/utils/request-utils.js
@@ -310,23 +310,28 @@ function getUrlDetails(url) {
  * @param {string} query - query string of a url portion
  * @return {array} array of query params { name, value }
  */
 function parseQueryString(query) {
   if (!query) {
     return null;
   }
 
-  return query.replace(/^[?&]/, "").split("&").map(e => {
-    const param = e.split("=");
-    return {
-      name: param[0] ? getUnicodeUrlPath(param[0]) : "",
-      value: param[1] ? getUnicodeUrlPath(param.slice(1).join("=")) : "",
-    };
-  });
+  return query
+    .replace(/^[?&]/, "")
+    .split("&")
+    .map(e => {
+      const param = e.split("=");
+      return {
+        name: param[0] ? getUnicodeUrlPath(param[0]) : "",
+        value: param[1]
+          ? getUnicodeUrlPath(param.slice(1).join("=")).replace(/\+/g, " ")
+          : "",
+      };
+    });
 }
 
 /**
  * Parse a string of formdata sections into its components
  *
  * @param {string} sections - sections of formdata joined by &
  * @return {array} array of formdata params { name, value }
  */
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -26,16 +26,17 @@ support-files =
   html_maps-test-page.html
   html_navigate-test-page.html
   html_params-test-page.html
   html_pause-test-page.html
   html_post-data-test-page.html
   html_post-array-data-test-page.html
   html_post-json-test-page.html
   html_post-raw-test-page.html
+  html_header-test-page.html
   html_post-raw-with-headers-test-page.html
   html_simple-test-page.html
   html_single-get-page.html
   html_send-beacon.html
   html_sorting-test-page.html
   html_statistics-test-page.html
   html_status-codes-test-page.html
   html_tracking-protection.html
@@ -133,16 +134,18 @@ skip-if = (os == 'mac') || (os == 'win' 
 [browser_net_filter-01.js]
 [browser_net_filter-02.js]
 [browser_net_filter-03.js]
 [browser_net_filter-04.js]
 [browser_net_filter-autocomplete.js]
 [browser_net_filter-flags.js]
 [browser_net_footer-summary.js]
 [browser_net_header-ref-policy.js]
+[browser_net_decode-url.js]
+[browser_net_decode-params.js]
 [browser_net_headers-alignment.js]
 [browser_net_headers_filter.js]
 [browser_net_headers_sorted.js]
 [browser_net_headers-resize.js]
 [browser_net_image-tooltip.js]
 [browser_net_json-b64.js]
 [browser_net_json-empty.js]
 [browser_net_json-null.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_decode-params.js
@@ -0,0 +1,39 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Tests if "+" is replaces with spaces in the Params panel.
+ */
+add_task(async function() {
+  const { tab, monitor } = await initNetMonitor(POST_RAW_URL_WITH_HASH);
+  info("Starting test... ");
+
+  const { document, store, windowRequire } = monitor.panelWin;
+  const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+  store.dispatch(Actions.batchEnable(false));
+
+  // Execute request.
+  await performRequests(monitor, tab, 1);
+
+  // Wait until the tab panel summary is displayed
+  wait = waitUntil(() =>
+    document.querySelectorAll(".tabpanel-summary-label")[0]);
+  EventUtils.sendMouseEvent({ type: "mousedown" },
+  document.querySelectorAll(".request-list-item")[0]);
+  await wait;
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector("#params-tab"));
+
+  // The Params panel should render the following:
+  // Query String:
+  // file    foo # bar
+  const keyValue = document.querySelectorAll(".treeTable .treeRow")[1];
+
+  is(keyValue.innerText,
+  "file\tfoo # bar", "'+' in params in correctly decoded.");
+
+  return teardown(monitor);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_decode-url.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Tests if "Request URL" containing "#" in its query is correctly decoded.
+ */
+add_task(async function() {
+  const { tab, monitor } = await initNetMonitor(POST_RAW_URL_WITH_HASH);
+  info("Starting test... ");
+
+  const { document, store, windowRequire } = monitor.panelWin;
+  const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+  store.dispatch(Actions.batchEnable(false));
+
+  // Execute request.
+  await performRequests(monitor, tab, 1);
+
+  // Wait until the tab panel summary is displayed
+  wait = waitUntil(() =>
+    document.querySelectorAll(".tabpanel-summary-label")[0]);
+  EventUtils.sendMouseEvent({ type: "mousedown" },
+  document.querySelectorAll(".request-list-item")[0]);
+  await wait;
+
+  const requestURL = document.querySelectorAll(".tabpanel-summary-value")[0];
+
+  is(requestURL.textContent.endsWith("foo+%23+bar"),
+  true, "\"Request URL\" containing '#' is correctly decoded.");
+
+  return teardown(monitor);
+});
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -50,16 +50,17 @@ const NAVIGATE_URL = EXAMPLE_URL + "html
 const CONTENT_TYPE_WITHOUT_CACHE_URL = EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
 const CONTENT_TYPE_WITHOUT_CACHE_REQUESTS = 8;
 const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";
 const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
 const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
 const POST_ARRAY_DATA_URL = EXAMPLE_URL + "html_post-array-data-test-page.html";
 const POST_JSON_URL = EXAMPLE_URL + "html_post-json-test-page.html";
 const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
+const POST_RAW_URL_WITH_HASH = EXAMPLE_URL + "html_header-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";
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/html_header-test-page.html
@@ -0,0 +1,43 @@
+<!-- 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>POST raw test</p>
+
+    <script type="text/javascript">
+      /* exported performRequests */
+      "use strict";
+
+      function post(address, message, callback) {
+        const xhr = new XMLHttpRequest();
+        xhr.open("POST", address, true);
+        xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
+
+        xhr.onreadystatechange = function() {
+          if (this.readyState == this.DONE) {
+            callback();
+          }
+        };
+        xhr.send(message);
+      }
+
+      function performRequests() {
+        const rawData = "";
+        post("sjs_simple-test-server.sjs?file=foo+%23+bar#home", rawData, function() {
+          // Done.
+        });
+      }
+    </script>
+  </body>
+
+</html>
--- a/devtools/client/shared/unicode-url.js
+++ b/devtools/client/shared/unicode-url.js
@@ -72,17 +72,17 @@ function getUnicodeUrlPath(urlPath) {
  *
  * If the `url` is a readable ASCII URL, such as http://example.org/a/b/c.js,
  * then this function will simply return the original `url`.
  *
  * If the `url` includes either an unreadable Punycode domain name or an
  * unreadable URI-encoded pathname, such as
  * http://xn--g6w.xn--8pv/%E8%A9%A6/%E6%B8%AC.js, then this function will return
  * the readable URL by decoding all its unreadable URL components to Unicode
- * characters.
+ * characters. The character `#` is not decoded from escape sequences.
  *
  * If the `url` is a malformed URL, then this function will return the original
  * `url`.
  *
  * If the `url` is a data: URI, then this function will return the original
  * `url`.
  *
  * @param {string}  url
@@ -95,17 +95,17 @@ function getUnicodeUrlPath(urlPath) {
 function getUnicodeUrl(url) {
   try {
     const { protocol, hostname } = new URL(url);
     if (protocol === "data:") {
       // Never convert a data: URI.
       return url;
     }
     const readableHostname = getUnicodeHostname(hostname);
-    url = decodeURIComponent(url);
+    url = decodeURI(url);
     return url.replace(hostname, readableHostname);
   } catch (err) {
   }
   return url;
 }
 
 module.exports = {
   getUnicodeHostname,