Bug 1452715 - Add support for same-site cookie attribute to "Cookies" netmonitor side-panel; r=Honza
MozReview-Commit-ID: ESP8L9vqNjU
--- 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.
}
}