Bug 1452715 - Add support for same-site cookie attribute to "Cookies" netmonitor side-panel; r=Honza draft
authorVincent Lequertier <vi.le@autistici.org>
Sat, 05 May 2018 18:24:20 +0200
changeset 794573 3d25dce7298b2464cd3ca84a75b87187e1a093f1
parent 794572 a7461494a7a0bb3d80c1449c1d5d484d8b568d98
push id109716
push uservi.le@autistici.org
push dateSun, 13 May 2018 12:17:04 +0000
reviewersHonza
bugs1452715
milestone62.0a1
Bug 1452715 - Add support for same-site cookie attribute to "Cookies" netmonitor side-panel; r=Honza MozReview-Commit-ID: ESP8L9vqNjU
devtools/client/netmonitor/test/browser.ini
devtools/client/netmonitor/test/browser_net_set-cookie-same-site.js
devtools/client/netmonitor/test/head.js
devtools/client/netmonitor/test/sjs_set-cookie-same-site.sjs
devtools/shared/webconsole/network-helper.js
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -42,16 +42,17 @@ support-files =
   html_curl-utils.html
   html_open-request-in-tab.html
   sjs_content-type-test-server.sjs
   sjs_cors-test-server.sjs
   sjs_https-redirect-test-server.sjs
   sjs_hsts-test-server.sjs
   sjs_json-test-server.sjs
   sjs_method-test-server.sjs
+  sjs_set-cookie-same-site.sjs
   sjs_simple-test-server.sjs
   sjs_simple-unsorted-cookies-test-server.sjs
   sjs_sorting-test-server.sjs
   sjs_status-codes-test-server.sjs
   sjs_truncate-test-server.sjs
   test-image.png
   service-workers/status-codes.html
   service-workers/status-codes-service-worker.js
@@ -168,16 +169,17 @@ skip-if = os == 'win' # bug 1391264
 [browser_net_security-icon-click.js]
 [browser_net_security-redirect.js]
 [browser_net_security-state.js]
 [browser_net_security-tab-deselect.js]
 [browser_net_security-tab-visibility.js]
 [browser_net_security-warnings.js]
 [browser_net_send-beacon.js]
 [browser_net_send-beacon-other-tab.js]
+[browser_net_set-cookie-same-site.js]
 [browser_net_simple-request-data.js]
 [browser_net_simple-request-details.js]
 skip-if = true # Bug 1258809
 [browser_net_simple-request.js]
 [browser_net_sort-01.js]
 [browser_net_sort-02.js]
 [browser_net_statistics-01.js]
 skip-if = true # Bug 1373558
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_set-cookie-same-site.js
@@ -0,0 +1,74 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Test if the 'Same site' cookie attribute is correctly set in the cookie panel
+ */
+add_task(async function() {
+  let { tab, monitor } = await initNetMonitor(SET_COOKIE_SAME_SITE_SJS);
+  info("Starting test... ");
+
+  let { document, store, windowRequire } = monitor.panelWin;
+  let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+
+  store.dispatch(Actions.batchEnable(false));
+  tab.linkedBrowser.reload();
+
+  let wait = waitForNetworkEvents(monitor, 1);
+  await wait;
+
+  wait = waitForDOM(document, ".headers-overview");
+  EventUtils.sendMouseEvent({ type: "mousedown" },
+    document.querySelectorAll(".request-list-item")[0]);
+  await wait;
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector("#cookies-tab"));
+
+  info("Checking the SameSite property");
+  const expectedValues = [
+    {
+        key: "Response cookies",
+        value: ""
+    },
+    {
+        key: "foo",
+        value: ""
+    },
+    {
+        key: "samesite",
+        value: "Lax"
+    },
+    {
+        key: "value",
+        value: "bar"
+    },
+    {
+        key: "Request cookies",
+        value: ""
+    },
+    {
+        key: "foo",
+        value: "bar"
+    },
+  ];
+  let labelCells = document.querySelectorAll(".treeLabelCell");
+  let valueCells = document.querySelectorAll(".treeValueCell");
+  is(valueCells.length, labelCells.length, "Number of labels "
+        + labelCells.length + " different from number of values " + valueCells.length);
+
+  // Go through the cookie properties and check if each one has the expected
+  // label and value
+  for (let index = 0; index < labelCells.length; ++index) {
+    is(labelCells[index].innerText, expectedValues[index].key,
+    "Actual label " + labelCells[index].innerText
+      + " not equal to expected label " + expectedValues[index].key);
+    is(valueCells[index].innerText, expectedValues[index].value,
+    "Actual value " + valueCells[index].innerText
+      + " not equal to expected value " + expectedValues[index].value);
+  }
+
+  await teardown(monitor);
+});
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -80,16 +80,17 @@ const CONTENT_TYPE_SJS = EXAMPLE_URL + "
 const HTTPS_CONTENT_TYPE_SJS = HTTPS_EXAMPLE_URL + "sjs_content-type-test-server.sjs";
 const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
 const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
 const HTTPS_REDIRECT_SJS = EXAMPLE_URL + "sjs_https-redirect-test-server.sjs";
 const CORS_SJS_PATH = "/browser/devtools/client/netmonitor/test/sjs_cors-test-server.sjs";
 const HSTS_SJS = EXAMPLE_URL + "sjs_hsts-test-server.sjs";
 const METHOD_SJS = EXAMPLE_URL + "sjs_method-test-server.sjs";
 const SLOW_SJS = EXAMPLE_URL + "sjs_slow-test-server.sjs";
+const SET_COOKIE_SAME_SITE_SJS = EXAMPLE_URL + "sjs_set-cookie-same-site.sjs";
 
 const HSTS_BASE_URL = EXAMPLE_URL;
 const HSTS_PAGE_URL = CUSTOM_GET_URL;
 
 const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
 const TEST_IMAGE_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
 
 /* eslint-enable no-unused-vars, max-len */
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/sjs_set-cookie-same-site.sjs
@@ -0,0 +1,10 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function handleRequest(request, response) {
+  response.setStatusLine(request.httpVersion, 200, "Och Aye");
+
+  response.setHeader("Set-Cookie", "foo=bar; SameSite=Lax");
+
+  response.write("Hello world!");
+}
--- a/devtools/shared/webconsole/network-helper.js
+++ b/devtools/shared/webconsole/network-helper.js
@@ -64,16 +64,24 @@ loader.lazyImporter(this, "NetUtil", "re
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const Services = require("Services");
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const L10N = new LocalizationHelper("devtools/client/locales/netmonitor.properties");
 
 // The cache used in the `nsIURL` function.
 const gNSURLStore = new Map();
 
+// "Lax", "Strict" and "Unset" are special values of the SameSite cookie
+// attribute that should not be translated.
+const COOKIE_SAMESITE = {
+  LAX: "Lax",
+  STRICT: "Strict",
+  UNSET: "Unset"
+};
+
 /**
  * Helper object for networking stuff.
  *
  * Most of the following functions have been taken from the Firebug source. They
  * have been modified to match the Firefox coding rules.
  */
 var NetworkHelper = {
   /**
@@ -348,19 +356,30 @@ var NetworkHelper = {
   /**
    * Parse a raw Set-Cookie header value.
    *
    * @param string header
    *        The raw Set-Cookie header value.
    * @return array
    *         Array holding an object for each cookie. Each object holds the
    *         following properties: name, value, secure (boolean), httpOnly
-   *         (boolean), path, domain and expires (ISO date string).
+   *         (boolean), path, domain, samesite and expires (ISO date string).
    */
   parseSetCookieHeader: function(header) {
+    function parseSameSiteAttribute(attribute) {
+      switch (attribute) {
+        case COOKIE_SAMESITE.LAX:
+          return COOKIE_SAMESITE.LAX;
+        case COOKIE_SAMESITE.STRICT:
+          return COOKIE_SAMESITE.STRICT;
+        default:
+          return COOKIE_SAMESITE.UNSET;
+      }
+    }
+
     let rawCookies = header.split(/\r\n|\n|\r/);
     let cookies = [];
 
     rawCookies.forEach(function(cookie) {
       let equal = cookie.indexOf("=");
       let name = unescape(cookie.substr(0, equal).trim());
       let parts = cookie.substr(equal + 1).split(";");
       let value = unescape(parts.shift().trim());
@@ -373,16 +392,18 @@ var NetworkHelper = {
           cookie.secure = true;
         } else if (part.toLowerCase() == "httponly") {
           cookie.httpOnly = true;
         } else if (part.indexOf("=") > -1) {
           let pair = part.split("=");
           pair[0] = pair[0].toLowerCase();
           if (pair[0] == "path" || pair[0] == "domain") {
             cookie[pair[0]] = pair[1];
+          } else if (pair[0] == "samesite") {
+            cookie[pair[0]] = parseSameSiteAttribute(pair[1]);
           } else if (pair[0] == "expires") {
             try {
               pair[1] = pair[1].replace(/-/g, " ");
               cookie.expires = new Date(pair[1]).toISOString();
             } catch (ex) {
               // Ignore.
             }
           }