Bug 1541670 [wpt PR 16148] - Send `Sec-Fetch-User` only for user-activated, navigational requests., a=testonly
authorMike West <mkwst@chromium.org>
Sun, 28 Apr 2019 08:36:19 +0000
changeset 531400 595f9f3aa36e9e4e5c8f120d7349c2965613814d
parent 531399 26073cb99912551ee558803060ad635a86a65447
child 531401 3ce7fdd9eddcdf30928cf283d84a9767495bc9f0
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1541670, 16148, 947444, 1545871, 646086
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 1541670 [wpt PR 16148] - Send `Sec-Fetch-User` only for user-activated, navigational requests., a=testonly Automatic update from web-platform-tests Send `Sec-Fetch-User` only for user-activated, navigational requests. As per the conversation in mikewest/sec-metadata#23 and mikewest/sec-metadata#19, this patch drops the `Sec-Fetch-User` header for non-navigational requests, and for navigational requests that are not user-activated. Bug: 947444 Change-Id: Ica4846bda6ccf4e8bce1323803954f4fef9c18a3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1545871 Reviewed-by: Alex Moshchuk <alexmos@chromium.org> Commit-Queue: Mike West <mkwst@chromium.org> Cr-Commit-Position: refs/heads/master@{#646086} -- wpt-commits: b93752a06f9498f774aed288663259cd738f1a7c wpt-pr: 16148
testing/web-platform/tests/fetch/sec-metadata/embed.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/fetch.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/font.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/iframe.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/img.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/object.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/report.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/script.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/serviceworker.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/sharedworker.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/style.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/track.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/trailing-dot.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/window-open.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/worker.tentative.https.sub.html
testing/web-platform/tests/fetch/sec-metadata/xslt.tentative.https.sub.html
--- a/testing/web-platform/tests/fetch/sec-metadata/embed.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/embed.tentative.https.sub.html
@@ -11,17 +11,17 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "embed-same-origin" + nonce;
 
       let e = document.createElement('embed');
       e.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.onload = e => {
-        let expected = {"dest":"embed", "site":"same-origin", "user":"?F", "mode":"no-cors"};
+        let expected = {"dest":"embed", "site":"same-origin", "user":"", "mode":"no-cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
 
       document.body.appendChild(e);
@@ -30,17 +30,17 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "embed-same-site" + nonce;
 
       let e = document.createElement('embed');
       e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.onload = e => {
-        let expected = {"dest":"embed", "site":"same-site", "user":"?F", "mode":"no-cors"};
+        let expected = {"dest":"embed", "site":"same-site", "user":"", "mode":"no-cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
 
       document.body.appendChild(e);
@@ -49,17 +49,17 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "embed-cross-site" + nonce;
 
       let e = document.createElement('embed');
       e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.onload = e => {
-        let expected = {"dest":"embed", "site":"cross-site", "user":"?F", "mode":"no-cors"};
+        let expected = {"dest":"embed", "site":"cross-site", "user":"", "mode":"no-cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
 
       document.body.appendChild(e);
--- a/testing/web-platform/tests/fetch/sec-metadata/fetch.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/fetch.tentative.https.sub.html
@@ -6,80 +6,80 @@
   // Site
   promise_test(t => {
     return fetch("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py")
         .then(r => r.json())
         .then(j => {
           assert_header_equals(j, {
             "dest": "empty",
             "site": "same-origin",
-            "user": "?F",
+            "user": "",
             "mode": "cors",
           });
         });
   }, "Same-origin fetch");
 
   promise_test(t => {
     return fetch("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py")
         .then(r => r.json())
         .then(j => {
           assert_header_equals(j, {
             "dest": "empty",
             "site": "same-site",
-            "user": "?F",
+            "user": "",
             "mode": "cors",
           });
         });
   }, "Same-site fetch");
 
   promise_test(t => {
     return fetch("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py")
         .then(r => r.json())
         .then(j => {
           assert_header_equals(j, {
             "dest": "empty",
             "site": "cross-site",
-            "user": "?F",
+            "user": "",
             "mode": "cors",
           });
         });
   }, "Cross-site fetch");
 
   // Mode
   promise_test(t => {
     return fetch("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py", {mode: "same-origin"})
         .then(r => r.json())
         .then(j => {
           assert_header_equals(j, {
             "dest": "empty",
             "site": "same-origin",
-            "user": "?F",
+            "user": "",
             "mode": "same-origin",
           });
         });
   }, "Same-origin mode");
 
   promise_test(t => {
     return fetch("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py", {mode: "cors"})
         .then(r => r.json())
         .then(j => {
           assert_header_equals(j, {
             "dest": "empty",
             "site": "same-origin",
-            "user": "?F",
+            "user": "",
             "mode": "cors",
           });
         });
   }, "CORS mode");
 
   promise_test(t => {
     return fetch("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py", {mode: "no-cors"})
         .then(r => r.json())
         .then(j => {
           assert_header_equals(j, {
             "dest": "empty",
             "site": "same-origin",
-            "user": "?F",
+            "user": "",
             "mode": "no-cors",
           });
         });
   }, "no-CORS mode");
 </script>
--- a/testing/web-platform/tests/fetch/sec-metadata/font.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/font.tentative.https.sub.html
@@ -41,41 +41,41 @@
     }
   </style>
 </body>
 <script>
   document.fonts.ready.then(function () {
     promise_test(t => {
       return new Promise((resolve, reject) => {
         let key = "font-same-origin";
-        let expected = {"dest":"font", "site":"same-origin", "user":"?F", "mode": "cors"};
+        let expected = {"dest":"font", "site":"same-origin", "user":"", "mode": "cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
         });
     }, "Same-Origin font");
 
     promise_test(t => {
       return new Promise((resolve, reject) => {
         let key = "font-same-site";
-        let expected = {"dest":"font", "site":"same-site", "user":"?F", "mode": "cors"};
+        let expected = {"dest":"font", "site":"same-site", "user":"", "mode": "cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
         });
     }, "Same-Site font");
 
     promise_test(t => {
       return new Promise((resolve, reject) => {
         let key = "font-cross-site";
-        let expected = {"dest":"font", "site":"cross-site", "user":"?F", "mode": "cors"};
+        let expected = {"dest":"font", "site":"cross-site", "user":"", "mode": "cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
         });
     }, "Cross-Site font");
 
--- a/testing/web-platform/tests/fetch/sec-metadata/iframe.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/iframe.tentative.https.sub.html
@@ -1,63 +1,85 @@
 <!DOCTYPE html>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-vendor.js></script>
 <script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/common/utils.js></script>
 <body>
 <script>
-  async_test(t => {
-    let i = document.createElement('iframe');
-    i.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py";
-    window.addEventListener('message', t.step_func(e => {
-      if (e.source != i.contentWindow)
-        return;
+  const USER = true;
+  const FORCED = false;
+
+  function create_test(host, user_activated, expectations) {
+    async_test(t => {
+      let i = document.createElement('iframe');
+      window.addEventListener('message', t.step_func(e => {
+        if (e.source != i.contentWindow)
+          return;
+
+        assert_header_equals(e.data, expectations);
+        t.done();
+      }));
 
-      assert_header_equals(e.data, {
-        "dest": "nested-document",
-        "site": "same-origin",
-        "user": "?F",
-        "mode": "nested-navigate"
-      });
-      t.done();
-    }));
+      let url = `https://${host}/fetch/sec-metadata/resources/post-to-owner.py`;
+      if (user_activated == FORCED) {
+        i.src = url;
+        document.body.appendChild(i);
+      } else if (user_activated == USER) {
+        let uuid = token();
+        i.name = uuid;
+        let a = document.createElement('a');
+        a.href = url;
+        a.target = uuid;
+        a.text = "This is a link!";
 
-    document.body.appendChild(i);
-  }, "Same-origin iframe");
+        document.body.appendChild(i);
+        document.body.appendChild(a);
 
-  async_test(t => {
-    let i = document.createElement('iframe');
-    i.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py";
-    window.addEventListener('message', t.step_func(e => {
-      if (e.source != i.contentWindow)
-        return;
+        test_driver.click(a);
+      }
+    }, `{{host}} -> ${host} iframe: ${user_activated ? "user-activated" : "forced"}`);
+  }
 
-      assert_header_equals(e.data, {
-        "dest": "nested-document",
-        "site": "same-site",
-        "user": "?F",
-        "mode": "nested-navigate"
-      });
-      t.done();
-    }));
+  create_test("{{host}}:{{ports[https][0]}}", FORCED, {
+    "dest": "nested-document",
+    "site": "same-origin",
+    "user": "",
+    "mode": "nested-navigate"
+  });
 
-    document.body.appendChild(i);
-  }, "Same-site iframe");
+  create_test("{{hosts[][www]}}:{{ports[https][0]}}", FORCED, {
+    "dest": "nested-document",
+    "site": "same-site",
+    "user": "",
+    "mode": "nested-navigate"
+  });
+
+  create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", FORCED, {
+    "dest": "nested-document",
+    "site": "cross-site",
+    "user": "",
+    "mode": "nested-navigate"
+  });
 
-  async_test(t => {
-    let i = document.createElement('iframe');
-    i.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py";
-    window.addEventListener('message', t.step_func(e => {
-      if (e.source != i.contentWindow)
-        return;
+  create_test("{{host}}:{{ports[https][0]}}", USER, {
+    "dest": "nested-document",
+    "site": "same-origin",
+    "user": "?T",
+    "mode": "nested-navigate"
+  });
 
-      assert_header_equals(e.data, {
-        "dest": "nested-document",
-        "site": "cross-site",
-        "user": "?F",
-        "mode": "nested-navigate"
-      });
-      t.done();
-    }));
+  create_test("{{hosts[][www]}}:{{ports[https][0]}}", USER, {
+    "dest": "nested-document",
+    "site": "same-site",
+    "user": "?T",
+    "mode": "nested-navigate"
+  });
 
-    document.body.appendChild(i);
-  }, "Cross-site iframe");
+  create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", USER, {
+    "dest": "nested-document",
+    "site": "cross-site",
+    "user": "?T",
+    "mode": "nested-navigate"
+  });
 </script>
--- a/testing/web-platform/tests/fetch/sec-metadata/img.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/img.tentative.https.sub.html
@@ -18,17 +18,19 @@
           "dest": headers["sec-fetch-dest"],
           "mode": headers["sec-fetch-mode"],
           "site": headers["sec-fetch-site"],
           "user": headers["sec-fetch-user"]
         };
         assert_header_equals(got, {
           "dest": "image",
           "site": "same-origin",
-          "user": "?F",
+          // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way
+          // that `image.py` encodes data.
+          "user": undefined,
           "mode": "cors", // Because `loadImageInWindow` tacks on `crossorigin`
         });
       }),
     "Same-origin image");
 
   promise_test(() =>
     loadImageInWindow(
       "https://{{hosts[][www]}}:{{ports[https][0]}}/referrer-policy/generic/subresource/image.py",
@@ -40,17 +42,19 @@
           "dest": headers["sec-fetch-dest"],
           "mode": headers["sec-fetch-mode"],
           "site": headers["sec-fetch-site"],
           "user": headers["sec-fetch-user"]
         };
         assert_header_equals(got, {
           "dest": "image",
           "site": "same-site",
-          "user": "?F",
+          // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way
+          // that `image.py` encodes data.
+          "user": undefined,
           "mode": "cors", // Because `loadImageInWindow` tacks on `crossorigin`
         });
       }),
     "Same-site image");
 
   promise_test(() =>
     loadImageInWindow(
       "https://{{hosts[alt][www]}}:{{ports[https][0]}}/referrer-policy/generic/subresource/image.py",
@@ -62,14 +66,16 @@
           "dest": headers["sec-fetch-dest"],
           "mode": headers["sec-fetch-mode"],
           "site": headers["sec-fetch-site"],
           "user": headers["sec-fetch-user"]
         };
         assert_header_equals(got, {
           "dest": "image",
           "site": "cross-site",
-          "user": "?F",
+          // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way
+          // that `image.py` encodes data.
+          "user": undefined,
           "mode": "cors", // Because `loadImageInWindow` tacks on `crossorigin`
         });
       }),
     "Cross-site image");
 </script>
--- a/testing/web-platform/tests/fetch/sec-metadata/object.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/object.tentative.https.sub.html
@@ -11,17 +11,17 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "object-same-origin" + nonce;
 
       let e = document.createElement('object');
       e.data = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.onload = e => {
-        let expected = {"dest":"object", "site":"same-origin", "user":"?F", "mode":"no-cors"};
+        let expected = {"dest":"object", "site":"same-origin", "user":"", "mode":"no-cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
 
       document.body.appendChild(e);
@@ -30,17 +30,17 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "object-same-site" + nonce;
 
       let e = document.createElement('object');
       e.data = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.onload = e => {
-        let expected = {"dest":"object", "site":"same-site", "user":"?F", "mode":"no-cors"};
+        let expected = {"dest":"object", "site":"same-site", "user":"", "mode":"no-cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
 
       document.body.appendChild(e);
@@ -49,17 +49,17 @@
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "object-cross-site" + nonce;
 
       let e = document.createElement('object');
       e.data = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.onload = e => {
-        let expected = {"dest":"object", "site":"cross-site", "user":"?F", "mode":"no-cors"};
+        let expected = {"dest":"object", "site":"cross-site", "user":"", "mode":"no-cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
 
       document.body.appendChild(e);
--- a/testing/web-platform/tests/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html
@@ -10,17 +10,17 @@
   let nonce = token();
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-cross-site-same-origin" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
-      let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"};
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
       e.onerror = e => {
@@ -36,17 +36,17 @@
   }, "Cross-Site -> Same-Origin redirect");
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-cross-site-same-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
-      let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"};
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
       e.onerror = e => {
@@ -62,17 +62,17 @@
   }, "Cross-Site -> Same-Site redirect");
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-cross-site-cross-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
-      let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"};
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
       e.onerror = e => {
--- a/testing/web-platform/tests/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html
@@ -12,17 +12,17 @@
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-multiple-cross-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin
       "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// cross-site
       "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;// same-origin
-      let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
--- a/testing/web-platform/tests/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html
@@ -12,17 +12,17 @@
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-multiple-same-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin
       "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-site
       "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;// same-origin
-      let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
--- a/testing/web-platform/tests/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html
@@ -10,17 +10,17 @@
   let nonce = token();
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-same-origin-same-origin" + nonce;
 
       let e = document.createElement('img');
       e.src = "/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
-      let expected = {"dest":"image", "site":"same-origin", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"same-origin", "user":"", "mode": "no-cors"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
@@ -37,17 +37,17 @@
   }, "Same-Origin -> Same-Origin redirect");
 
 promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-same-origin-same-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
-      let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
@@ -64,17 +64,17 @@ promise_test(t => {
   }, "Same-Origin -> Same-Site redirect");
 
 promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-same-origin-cross-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
-      let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
--- a/testing/web-platform/tests/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html
@@ -10,17 +10,17 @@
   let nonce = token();
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-same-site-same-origin" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
-      let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
@@ -37,17 +37,17 @@
   }, "Same-Site -> Same-Origin redirect");
 
 promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-same-site-same-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
-      let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"same-site", "user":"", "mode": "no-cors"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
@@ -64,17 +64,17 @@ promise_test(t => {
   }, "Same-Site -> Same-Site redirect");
 
 promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "redirect-same-site-cross-site" + nonce;
 
       let e = document.createElement('img');
       e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
-      let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"", "mode": "no-cors"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
--- a/testing/web-platform/tests/fetch/sec-metadata/report.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/report.tentative.https.sub.html
@@ -17,16 +17,16 @@
       }, 1000);
     }, name + " report");
   }
 
   let counter = 0;
   document.addEventListener("securitypolicyviolation", (e) => {
     counter++;
     if (counter == 3) {
-      generate_test({"dest":"report", "site":"same-origin", "user":"?F", "mode": "no-cors"}, "same-origin");
-      generate_test({"dest":"report", "site":"same-site", "user":"?F", "mode": "no-cors"}, "same-site");
-      generate_test({"dest":"report", "site":"cross-site", "user":"?F", "mode": "no-cors"}, "cross-site");
+      generate_test({"dest":"report", "site":"same-origin", "user":"", "mode": "no-cors"}, "same-origin");
+      generate_test({"dest":"report", "site":"same-site", "user":"", "mode": "no-cors"}, "same-site");
+      generate_test({"dest":"report", "site":"cross-site", "user":"", "mode": "no-cors"}, "cross-site");
 
       done();
     }
   });
 </script>
--- a/testing/web-platform/tests/fetch/sec-metadata/script.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/script.tentative.https.sub.html
@@ -7,58 +7,58 @@
 <script src="https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-script.py"></script>
 <script>
   test(t => {
     t.add_cleanup(_ => { header = null; });
 
     assert_header_equals(header, {
       "dest": "script",
       "site": "same-origin",
-      "user": "?F",
+      "user": "",
       "mode": "no-cors",
     });
   }, "Same-origin script");
 </script>
 
 <!-- Same-site script -->
 <script src="https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-script.py"></script>
 <script>
   test(t => {
     t.add_cleanup(_ => { header = null; });
 
     assert_header_equals(header, {
       "dest": "script",
       "site": "same-site",
-      "user": "?F",
+      "user": "",
       "mode": "no-cors",
     });
   }, "Same-site script");
 </script>
 
 <!-- Cross-site script -->
 <script src="https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-script.py"></script>
 <script>
   test(t => {
     t.add_cleanup(_ => { header = null; });
 
     assert_header_equals(header, {
       "dest": "script",
       "site": "cross-site",
-      "user": "?F",
+      "user": "",
       "mode": "no-cors",
     });
   }, "Cross-site script");
 </script>
 
 <!-- Same-origin script, CORS mode -->
 <script src="https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-script.py" crossorigin="anonymous"></script>
 <script>
   test(t => {
     t.add_cleanup(_ => { header = null; });
 
     assert_header_equals(header, {
       "dest": "script",
       "site": "same-origin",
-      "user": "?F",
+      "user": "",
       "mode": "cors",
     });
   }, "Same-origin CORS script");
 </script>
--- a/testing/web-platform/tests/fetch/sec-metadata/serviceworker.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/serviceworker.tentative.https.sub.html
@@ -33,17 +33,17 @@
       }
   </script>
 </body>
 
 <script>
   function test_same_origin(){
     promise_test(t => {
     return new Promise((resolve, reject) => {
-      let expected = {"dest":"serviceworker", "site":"same-origin", "user":"?F", "mode": "same-origin"};
+      let expected = {"dest":"serviceworker", "site":"same-origin", "user":"", "mode": "same-origin"};
       fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
         .then(response => response.text())
         .then(text => assert_header_equals(text, expected))
         .then(_ => resolve())
         .catch(e => reject(e));
       })
     })
   }
--- a/testing/web-platform/tests/fetch/sec-metadata/sharedworker.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/sharedworker.tentative.https.sub.html
@@ -23,17 +23,17 @@
         test_same_origin();
       }
       sharedWorker.port.postMessage("Ready");
     }
 
   function test_same_origin(){
     promise_test(t => {
       return new Promise((resolve, reject) => {
-        let expected = {"dest":"sharedworker", "site":"same-origin", "user":"?F", "mode": "same-origin"};
+        let expected = {"dest":"sharedworker", "site":"same-origin", "user":"", "mode": "same-origin"};
 
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       })
     }, "Same-Origin sharedworker")
--- a/testing/web-platform/tests/fetch/sec-metadata/style.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/style.tentative.https.sub.html
@@ -12,17 +12,17 @@
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "style-same-origin" + nonce;
 
       let e = document.createElement('link');
       e.rel = "stylesheet";
       e.href = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.onload = e => {
-        let expected = {"dest":"style", "site":"same-origin", "user":"?F", "mode": "no-cors"};
+        let expected = {"dest":"style", "site":"same-origin", "user":"", "mode": "no-cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
 
       document.body.appendChild(e);
@@ -32,17 +32,17 @@
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "style-same-site" + nonce;
 
       let e = document.createElement('link');
       e.rel = "stylesheet";
       e.href = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.onload = e => {
-        let expected = {"dest":"style", "site":"same-site", "user":"?F", "mode": "no-cors"};
+        let expected = {"dest":"style", "site":"same-site", "user":"", "mode": "no-cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
 
       document.body.appendChild(e);
@@ -52,17 +52,17 @@
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "style-cross-site" + nonce;
 
       let e = document.createElement('link');
       e.rel = "stylesheet";
       e.href = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.onload = e => {
-        let expected = {"dest":"style", "site":"cross-site", "user":"?F", "mode": "no-cors"};
+        let expected = {"dest":"style", "site":"cross-site", "user":"", "mode": "no-cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
 
       document.body.appendChild(e);
@@ -73,17 +73,17 @@
     return new Promise((resolve, reject) => {
       let key = "style-same-origin-cors" + nonce;
 
       let e = document.createElement('link');
       e.rel = "stylesheet";
       e.href = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.crossOrigin = "anonymous";
       e.onload = e => {
-        let expected = {"dest":"style", "site":"same-origin", "user":"?F", "mode": "cors"};
+        let expected = {"dest":"style", "site":"same-origin", "user":"", "mode": "cors"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
 
       document.body.appendChild(e);
--- a/testing/web-platform/tests/fetch/sec-metadata/track.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/track.tentative.https.sub.html
@@ -31,17 +31,17 @@
       let key = "track-same-origin" + nonce;
       let video = createVideoElement();
       let el = createTrack();
       el.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       el.onload = t.step_func(_ => {
         expected = {
           "dest": "track",
           "site": "same-origin",
-          "user": "?F",
+          "user": "",
           "mode": "cors" // Because the `video` element has `crossorigin`
         };
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
             .then(_ => resolve());
       });
       video.appendChild(el);
@@ -54,17 +54,17 @@
       let key = "track-same-site" + nonce;
       let video = createVideoElement();
       let el = createTrack();
       el.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       el.onload = t.step_func(_ => {
         expected = {
           "dest": "track",
           "site": "same-site",
-          "user": "?F",
+          "user": "",
           "mode": "cors" // Because the `video` element has `crossorigin`
         };
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
             .then(resolve)
             .catch(reject);
 
@@ -79,17 +79,17 @@
       let key = "track-cross-site" + nonce;
       let video = createVideoElement();
       let el = createTrack();
       el.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       el.onload = t.step_func(_ => {
         expected = {
           "dest": "track",
           "site": "cross-site",
-          "user": "?F",
+          "user": "",
           "mode": "cors" // Because the `video` element has `crossorigin`
         };
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
             .then(resolve)
             .catch(reject);
       });
@@ -107,17 +107,17 @@
       video.crossOrigin = undefined;
 
       let el = createTrack();
       el.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       el.onload = t.step_func(_ => {
         expected = {
           "dest":"track",
           "site":"same-origin",
-          "user":"?F",
+          "user":"",
           "mode": "same-origin"
         };
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
             .then(_ => resolve());
       });
       video.appendChild(el);
--- a/testing/web-platform/tests/fetch/sec-metadata/trailing-dot.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/trailing-dot.tentative.https.sub.html
@@ -6,40 +6,40 @@
   // Site
   promise_test(t => {
     return fetch("https://{{host}}.:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py")
         .then(r => r.json())
         .then(j => {
           assert_header_equals(j, {
             "dest": "empty",
             "site": "cross-site",
-            "user": "?F",
+            "user": "",
             "mode": "cors",
           });
         });
   }, "Fetching a resource from the same origin, but spelled with a trailing dot.");
 
   promise_test(t => {
     return fetch("https://{{hosts[][www]}}.:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py")
         .then(r => r.json())
         .then(j => {
           assert_header_equals(j, {
             "dest": "empty",
             "site": "cross-site",
-            "user": "?F",
+            "user": "",
             "mode": "cors",
           });
         });
   }, "Fetching a resource from the same site, but spelled with a trailing dot.");
 
   promise_test(t => {
     return fetch("https://{{hosts[alt][www]}}.:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py")
         .then(r => r.json())
         .then(j => {
           assert_header_equals(j, {
             "dest": "empty",
             "site": "cross-site",
-            "user": "?F",
+            "user": "",
             "mode": "cors",
           });
         });
   }, "Fetching a resource from a cross-site host, spelled with a trailing dot.");
 </script>
--- a/testing/web-platform/tests/fetch/sec-metadata/window-open.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/window-open.tentative.https.sub.html
@@ -12,51 +12,51 @@
     t.add_cleanup(_ => w.close());
     window.addEventListener('message', t.step_func(e => {
       if (e.source != w)
         return;
 
       assert_header_equals(e.data, {
         "dest": "document",
         "site": "same-origin",
-        "user": "?F",
+        "user": "",
         "mode": "navigate",
       });
       t.done();
     }));
   }, "Same-origin window, forced");
 
   async_test(t => {
     let w = window.open("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py");
     t.add_cleanup(_ => w.close());
     window.addEventListener('message', t.step_func(e => {
       if (e.source != w)
         return;
 
       assert_header_equals(e.data, {
         "dest": "document",
         "site": "same-site",
-        "user": "?F",
+        "user": "",
         "mode": "navigate",
       });
       t.done();
     }));
   }, "Same-site window, forced");
 
   async_test(t => {
     let w = window.open("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py");
     t.add_cleanup(_ => w.close());
     window.addEventListener('message', t.step_func(e => {
       if (e.source != w)
         return;
 
       assert_header_equals(e.data, {
         "dest": "document",
         "site": "cross-site",
-        "user": "?F",
+        "user": "",
         "mode": "navigate",
       });
       t.done();
     }));
   }, "Cross-site window, forced");
 
   async_test(t => {
     let w = window.open("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py");
@@ -65,17 +65,17 @@
     window.addEventListener('message', t.step_func(e => {
       messages++;
       if (e.source != w)
         return;
 
       assert_header_equals(e.data, {
         "dest": "document",
         "site": "same-origin",
-        "user": "?F",
+        "user": "",
         "mode": "navigate",
       });
 
       if (messages == 1) {
         w.location.reload();
       } else {
         t.done();
       }
@@ -89,17 +89,17 @@
     window.addEventListener('message', t.step_func(e => {
       messages++;
       if (e.source != w)
         return;
 
       assert_header_equals(e.data, {
         "dest": "document",
         "site": "same-site",
-        "user": "?F",
+        "user": "",
         "mode": "navigate",
       });
 
       if (messages == 1) {
         w.location.reload();
       } else {
         t.done();
       }
@@ -113,17 +113,17 @@
     window.addEventListener('message', t.step_func(e => {
       messages++;
       if (e.source != w)
         return;
 
       assert_header_equals(e.data, {
         "dest": "document",
         "site": "cross-site",
-        "user": "?F",
+        "user": "",
         "mode": "navigate",
       });
 
       if (messages == 1) {
         w.location.reload();
       } else {
         t.done();
       }
--- a/testing/web-platform/tests/fetch/sec-metadata/worker.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/worker.tentative.https.sub.html
@@ -8,17 +8,17 @@
 <script>
   let nonce = token();
 
   promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "worker-same-origin" + nonce;
       let w = new Worker("/fetch/sec-metadata/resources/record-header.py?file=" + key);
       w.onmessage = e => {
-        let expected = {"dest":"worker", "site":"same-origin", "user":"?F", "mode": "same-origin"};
+        let expected = {"dest":"worker", "site":"same-origin", "user":"", "mode": "same-origin"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
           .then(_ => resolve())
           .catch(e => reject(e));
       };
     });
   }, "Same-Origin worker");
--- a/testing/web-platform/tests/fetch/sec-metadata/xslt.tentative.https.sub.html
+++ b/testing/web-platform/tests/fetch/sec-metadata/xslt.tentative.https.sub.html
@@ -7,31 +7,31 @@
 <script>
   // Open a window with XML document which loads resources via <?xml-stylesheet/> tag
   let w = window.open("resources/xslt-test.sub.xml");
   window.addEventListener('message', function(e) {
     if (e.source != w)
       return;
 
     promise_test(t => {
-      let expected = {"dest":"xslt", "site":"same-origin", "user":"?F", "mode": "same-origin"};
+      let expected = {"dest":"xslt", "site":"same-origin", "user":"", "mode": "same-origin"};
       return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-same-origin")
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected));
     }, "Same-Origin xslt");
 
     promise_test(t => {
-      let expected = {"dest":"xslt", "site":"same-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"xslt", "site":"same-site", "user":"", "mode": "no-cors"};
       return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-same-site")
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected));
     }, "Same-site xslt");
 
     promise_test(t => {
-      let expected = {"dest":"xslt", "site":"cross-site", "user":"?F", "mode": "no-cors"};
+      let expected = {"dest":"xslt", "site":"cross-site", "user":"", "mode": "no-cors"};
       return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-cross-site")
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected));
     }, "Cross-site xslt");
 
     w.close();
   });