Split `Sec-Metadata` into `Sec-Fetch-*`.

As of [1], we've split the single `Sec-Metadata` header into multiple
headers: `Sec-Fetch-Dest`, `Sec-Fetch-Site`, and `Sec-Fetch-User`. This
patch does that work in Chromium.

The spec change also added `Sec-Fetch-Mode`, but this patch does not.
We'll add that functionality to Chromium in a future CL.

Test changes pulled from clap@'s excellent PR at
https://github.com/web-platform-tests/wpt/pull/14771

The test failures are expected: redirect failures are
https://crbug.com/872285, object/embed failures are
https://crbug.com/860510. XSLT failures are WontFix (some
engines support cross-origin XSLT; Blink does not).

[1]: https://github.com/mikewest/sec-metadata/commit/105103d775141912261dd164b16bd59b22f6d853

Bug: 843478
Change-Id: I7654d5e823ad813682ac3eb244bbc244a322e6ca
Reviewed-on: https://chromium-review.googlesource.com/c/1402448
Commit-Queue: Mike West <mkwst@chromium.org>
Reviewed-by: Camille Lamy <clamy@chromium.org>
Reviewed-by: Daniel Vogelheim <vogelheim@chromium.org>
Cr-Commit-Position: refs/heads/master@{#622145}
diff --git a/fetch/sec-metadata/embed.tentative.https.sub.html b/fetch/sec-metadata/embed.tentative.https.sub.html
index 745ef42..1c69c02 100644
--- a/fetch/sec-metadata/embed.tentative.https.sub.html
+++ b/fetch/sec-metadata/embed.tentative.https.sub.html
@@ -13,7 +13,7 @@
       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 = {"destination":"embed", "site":"same-origin"};
+        let expected = {"dest":"embed", "site":"same-origin", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
@@ -32,7 +32,7 @@
       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 = {"destination":"embed", "site":"same-site"};
+        let expected = {"dest":"embed", "site":"same-site", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
@@ -51,7 +51,7 @@
       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 = {"destination":"embed", "site":"cross-site"};
+        let expected = {"dest":"embed", "site":"cross-site", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
diff --git a/fetch/sec-metadata/fetch.tentative.https.sub.html b/fetch/sec-metadata/fetch.tentative.https.sub.html
index d18042c..f6460b4 100644
--- a/fetch/sec-metadata/fetch.tentative.https.sub.html
+++ b/fetch/sec-metadata/fetch.tentative.https.sub.html
@@ -7,10 +7,10 @@
     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.header, {
-            "cause": undefined,
-            "destination": "empty",
-            "site": "same-origin"
+          assert_header_equals(j, {
+            "dest": "empty",
+            "site": "same-origin",
+            "user":"?F"
           });
         });
   }, "Same-origin fetch");
@@ -19,10 +19,10 @@
     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.header, {
-            "cause": undefined,
-            "destination": "empty",
-            "site": "same-site"
+          assert_header_equals(j, {
+            "dest": "empty",
+            "site": "same-site",
+            "user":"?F"
           });
         });
   }, "Same-site fetch");
@@ -31,10 +31,10 @@
     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.header, {
-            "cause": undefined,
-            "destination": "empty",
-            "site": "cross-site"
+          assert_header_equals(j, {
+            "dest": "empty",
+            "site": "cross-site",
+            "user":"?F"
           });
         });
   }, "Cross-site fetch");
diff --git a/fetch/sec-metadata/font.tentative.https.sub.html b/fetch/sec-metadata/font.tentative.https.sub.html
index 0a75531..d2bcf69 100644
--- a/fetch/sec-metadata/font.tentative.https.sub.html
+++ b/fetch/sec-metadata/font.tentative.https.sub.html
@@ -46,7 +46,7 @@
     promise_test(t => {
       return new Promise((resolve, reject) => {
         let key = "font-same-origin";
-        let expected = {"destination":"font", "site":"same-origin"};
+        let expected = {"dest":"font", "site":"same-origin", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
@@ -58,7 +58,7 @@
     promise_test(t => {
       return new Promise((resolve, reject) => {
         let key = "font-same-site";
-        let expected = {"destination":"font", "site":"same-site"};
+        let expected = {"dest":"font", "site":"same-site", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
@@ -70,7 +70,7 @@
     promise_test(t => {
       return new Promise((resolve, reject) => {
         let key = "font-cross-site";
-        let expected = {"destination":"font", "site":"cross-site"};
+        let expected = {"dest":"font", "site":"cross-site", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
diff --git a/fetch/sec-metadata/iframe.tentative.https.sub.html b/fetch/sec-metadata/iframe.tentative.https.sub.html
index 8d89cda..6ee1430 100644
--- a/fetch/sec-metadata/iframe.tentative.https.sub.html
+++ b/fetch/sec-metadata/iframe.tentative.https.sub.html
@@ -12,9 +12,9 @@
         return;
 
       assert_header_equals(e.data, {
-        "cause": "forced",
-        "destination": "nested-document",
-        "site": "same-origin"
+        "dest": "nested-document",
+        "site": "same-origin",
+        "user":"?F"
       });
       t.done();
     }));
@@ -30,9 +30,9 @@
         return;
 
       assert_header_equals(e.data, {
-        "cause": "forced",
-        "destination": "nested-document",
-        "site": "same-site"
+        "dest": "nested-document",
+        "site": "same-site",
+        "user": "?F"
       });
       t.done();
     }));
@@ -48,9 +48,9 @@
         return;
 
       assert_header_equals(e.data, {
-        "cause": "forced",
-        "destination": "nested-document",
-        "site": "cross-site"
+        "dest": "nested-document",
+        "site": "cross-site",
+        "user": "?F"
       });
       t.done();
     }));
diff --git a/fetch/sec-metadata/img.tentative.https.sub.html b/fetch/sec-metadata/img.tentative.https.sub.html
index 20701a6..c5c3895 100644
--- a/fetch/sec-metadata/img.tentative.https.sub.html
+++ b/fetch/sec-metadata/img.tentative.https.sub.html
@@ -11,10 +11,17 @@
     loadImageInWindow(
       "https://{{host}}:{{ports[https][0]}}/referrer-policy/generic/subresource/image.py",
       t.step_func_done(img => {
-        assert_header_equals(decodeImageData(extractImageData(img)).headers["sec-metadata"], {
-          "cause": undefined,
-          "destination": "image",
-          "site": "same-origin"
+        headers = decodeImageData(extractImageData(img)).headers;
+        got = {
+        "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"
         });
       }),
       [],
@@ -25,10 +32,17 @@
     loadImageInWindow(
       "https://{{hosts[][www]}}:{{ports[https][0]}}/referrer-policy/generic/subresource/image.py",
       t.step_func_done(img => {
-        assert_header_equals(decodeImageData(extractImageData(img)).headers["sec-metadata"], {
-          "cause": undefined,
-          "destination": "image",
-          "site": "same-site"
+        headers = decodeImageData(extractImageData(img)).headers;
+        got = {
+        "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"
         });
       }),
       [],
@@ -39,10 +53,17 @@
     loadImageInWindow(
       "https://{{hosts[alt][www]}}:{{ports[https][0]}}/referrer-policy/generic/subresource/image.py",
       t.step_func_done(img => {
-        assert_header_equals(decodeImageData(extractImageData(img)).headers["sec-metadata"], {
-          "cause": undefined,
-          "destination": "image",
-          "site": "cross-site"
+        headers = decodeImageData(extractImageData(img)).headers;
+        got = {
+        "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"
         });
       }),
       [],
diff --git a/fetch/sec-metadata/object.tentative.https.sub.html b/fetch/sec-metadata/object.tentative.https.sub.html
index e1ac531..0b98394 100644
--- a/fetch/sec-metadata/object.tentative.https.sub.html
+++ b/fetch/sec-metadata/object.tentative.https.sub.html
@@ -13,7 +13,7 @@
       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 = {"destination":"object", "site":"same-origin"};
+        let expected = {"dest":"object", "site":"same-origin", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
@@ -32,7 +32,7 @@
       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 = {"destination":"object", "site":"same-site"};
+        let expected = {"dest":"object", "site":"same-site", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
@@ -51,7 +51,7 @@
       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 = {"destination":"object", "site":"cross-site"};
+        let expected = {"dest":"object", "site":"cross-site", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
diff --git a/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html b/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html
index 9f497a9..56d88d9 100644
--- a/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html
+++ b/fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html
@@ -12,7 +12,7 @@
 
       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 = {"destination":"image", "site":"cross-site"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
@@ -38,7 +38,7 @@
 
       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 = {"destination":"image", "site":"cross-site"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
@@ -64,7 +64,7 @@
 
       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 = {"destination":"image", "site":"cross-site"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
diff --git a/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html b/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html
index fdd8733..f6d18f5 100644
--- a/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html
+++ b/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html
@@ -14,7 +14,7 @@
       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 = {"destination":"image", "site":"cross-site"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
diff --git a/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html b/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html
index 8fdc943..4756a79 100644
--- a/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html
+++ b/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html
@@ -14,7 +14,7 @@
       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 = {"destination":"image", "site":"same-site"};
+      let expected = {"dest":"image", "site":"same-site", "user":"?F"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
diff --git a/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html b/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html
index dea71c3..8558d68 100644
--- a/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html
+++ b/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html
@@ -12,7 +12,7 @@
 
       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 = {"destination":"image", "site":"same-origin"};
+      let expected = {"dest":"image", "site":"same-origin", "user":"?F"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
@@ -39,7 +39,7 @@
 
       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 = {"destination":"image", "site":"same-site"};
+      let expected = {"dest":"image", "site":"same-site", "user":"?F"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
@@ -66,7 +66,7 @@
 
       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 = {"destination":"image", "site":"cross-site"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
diff --git a/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html b/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html
index a71163a..8e05b25 100644
--- a/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html
+++ b/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html
@@ -12,7 +12,7 @@
 
       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 = {"destination":"image", "site":"same-site"};
+      let expected = {"dest":"image", "site":"same-site", "user":"?F"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
@@ -39,7 +39,7 @@
 
       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 = {"destination":"image", "site":"same-site"};
+      let expected = {"dest":"image", "site":"same-site", "user":"?F"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
@@ -66,7 +66,7 @@
 
       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 = {"destination":"image", "site":"cross-site"};
+      let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
 
       e.onload = e => {
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
diff --git a/fetch/sec-metadata/report.tentative.https.sub.html b/fetch/sec-metadata/report.tentative.https.sub.html
index a74da6a..1cfa864 100644
--- a/fetch/sec-metadata/report.tentative.https.sub.html
+++ b/fetch/sec-metadata/report.tentative.https.sub.html
@@ -22,9 +22,9 @@
     document.addEventListener("securitypolicyviolation", (e) => {
       counter++;
       if (counter == 3) {
-        generate_test({"destination":"report", "site":"same-origin"}, "same-origin");
-        generate_test({"destination":"report", "site":"same-site"}, "same-site");
-        generate_test({"destination":"report", "site":"cross-site"}, "cross-site");
+        generate_test({"dest":"report", "site":"same-origin", "user":"?F"}, "same-origin");
+        generate_test({"dest":"report", "site":"same-site", "user":"?F"}, "same-site");
+        generate_test({"dest":"report", "site":"cross-site", "user":"?F"}, "cross-site");
       }
     });
   }, "Initialization.");
diff --git a/fetch/sec-metadata/resources/echo-as-json.py b/fetch/sec-metadata/resources/echo-as-json.py
index 16cc677..ce5a2d9 100644
--- a/fetch/sec-metadata/resources/echo-as-json.py
+++ b/fetch/sec-metadata/resources/echo-as-json.py
@@ -8,5 +8,10 @@
         headers.append(("Access-Control-Allow-Origin", request.headers["origin"]))
 
 
-    body = json.dumps({ "header": request.headers.get("sec-metadata", "") })
+    body = json.dumps({
+        "dest": request.headers.get("sec-fetch-dest", ""),
+        "mode": request.headers.get("sec-fetch-mode", ""),
+        "site": request.headers.get("sec-fetch-site", ""),
+        "user": request.headers.get("sec-fetch-user", ""),
+        })
     return headers, body
diff --git a/fetch/sec-metadata/resources/echo-as-script.py b/fetch/sec-metadata/resources/echo-as-script.py
index c1c6a46..7884b09 100644
--- a/fetch/sec-metadata/resources/echo-as-script.py
+++ b/fetch/sec-metadata/resources/echo-as-script.py
@@ -3,6 +3,11 @@
 def main(request, response):
     headers = [("Content-Type", "text/javascript")]
 
-    body = "var header = %s;" % json.dumps(request.headers.get("sec-metadata", ""));
+    body = "var header = %s;" % json.dumps({
+        "dest": request.headers.get("sec-fetch-dest", ""),
+        "mode": request.headers.get("sec-fetch-mode", ""),
+        "site": request.headers.get("sec-fetch-site", ""),
+        "user": request.headers.get("sec-fetch-user", ""),
+        });
 
     return headers, body
diff --git a/fetch/sec-metadata/resources/helper.js b/fetch/sec-metadata/resources/helper.js
index 037f7e1..1a9ec15 100644
--- a/fetch/sec-metadata/resources/helper.js
+++ b/fetch/sec-metadata/resources/helper.js
@@ -1,18 +1,11 @@
-function parse_metadata(value) {
-  let result = {};
-  value.split(',').forEach(item => {
-    let parsed = item.trim().split('=');
-    result[parsed[0]] = parsed[1];
-  });
-  return result;
-}
-
 function assert_header_equals(value, expected) {
-  // check that the returned value is an object, not a String
-  assert_not_equals(value, "", "Empty Sec-Metadata header.");
-  let result = parse_metadata(value);
-  assert_equals(result.cause, expected.cause, "cause");
-  assert_equals(result.destination, expected.destination, "destination");
-  assert_equals(result.target, expected.target, "target");
-  assert_equals(result.site, expected.site, "site");
+  if (typeof(value) === "string"){
+    assert_not_equals(value, "No header has been recorded");
+    value = JSON.parse(value);
+  }
+  assert_equals(value.dest, expected.dest, "dest");
+  // Mode is commented out as no test cases have been filled out yet
+  // assert_equals(value.mode, expected.mode, "mode");
+  assert_equals(value.site, expected.site, "site");
+  assert_equals(value.user, expected.user, "user");
 }
diff --git a/fetch/sec-metadata/resources/post-to-owner.py b/fetch/sec-metadata/resources/post-to-owner.py
index 5472aa5..81d4ebf 100644
--- a/fetch/sec-metadata/resources/post-to-owner.py
+++ b/fetch/sec-metadata/resources/post-to-owner.py
@@ -12,5 +12,10 @@
             if (window.top != window)
                 window.top.postMessage(data, "*");
         </script>
-    """ % json.dumps(request.headers.get("Sec-Metadata", ""))
+    """ % json.dumps({
+        "dest": request.headers.get("sec-fetch-dest", ""),
+        "mode": request.headers.get("sec-fetch-mode", ""),
+        "site": request.headers.get("sec-fetch-site", ""),
+        "user": request.headers.get("sec-fetch-user", ""),
+        })
     return headers, body
diff --git a/fetch/sec-metadata/resources/record-header.py b/fetch/sec-metadata/resources/record-header.py
index adf9a53..f215b01 100644
--- a/fetch/sec-metadata/resources/record-header.py
+++ b/fetch/sec-metadata/resources/record-header.py
@@ -2,6 +2,7 @@
 import uuid
 import hashlib
 import time
+import json
 
 def main(request, response):
   ## Get the query parameter (key) from URL ##
@@ -30,8 +31,14 @@
   ## Record incoming Sec-Metadata header value
   else:
     try:
-      ## Return empty string as a default value ##
-      header = request.headers.get("Sec-Metadata", "")
+      ## Return a serialized JSON object with one member per header. If the ##
+      ## header isn't present, the member will contain an empty string.     ##
+      header = json.dumps({
+        "dest": request.headers.get("sec-fetch-dest", ""),
+        "mode": request.headers.get("sec-fetch-mode", ""),
+        "site": request.headers.get("sec-fetch-site", ""),
+        "user": request.headers.get("sec-fetch-user", ""),
+      })
       request.server.stash.put(testId, header)
     except KeyError:
       ## The header is already recorded or it doesn't exist
diff --git a/fetch/sec-metadata/script.tentative.https.sub.html b/fetch/sec-metadata/script.tentative.https.sub.html
index 643e118..d76378f 100644
--- a/fetch/sec-metadata/script.tentative.https.sub.html
+++ b/fetch/sec-metadata/script.tentative.https.sub.html
@@ -10,9 +10,9 @@
     t.add_cleanup(_ => { header = null; });
 
     assert_header_equals(header, {
-      "cause": undefined,
-      "destination": "script",
-      "site": "same-origin"
+      "dest": "script",
+      "site": "same-origin",
+      "user":"?F"
     });
   }, "Same-origin script");
 </script>
@@ -24,9 +24,9 @@
     t.add_cleanup(_ => { header = null; });
 
     assert_header_equals(header, {
-      "cause": undefined,
-      "destination": "script",
-      "site": "same-site"
+      "dest": "script",
+      "site": "same-site",
+      "user":"?F"
     });
   }, "Same-site script");
 </script>
@@ -38,9 +38,9 @@
     t.add_cleanup(_ => { header = null; });
 
     assert_header_equals(header, {
-      "cause": undefined,
-      "destination": "script",
-      "site": "cross-site"
+      "dest": "script",
+      "site": "cross-site",
+      "user":"?F"
     });
   }, "Cross-site script");
 </script>
diff --git a/fetch/sec-metadata/serviceworker.tentative.https.sub.html b/fetch/sec-metadata/serviceworker.tentative.https.sub.html
index cefabb2..d0b86d2 100644
--- a/fetch/sec-metadata/serviceworker.tentative.https.sub.html
+++ b/fetch/sec-metadata/serviceworker.tentative.https.sub.html
@@ -35,7 +35,7 @@
     promise_test(t => {
     return new Promise((resolve, reject) => {
       let key = "serviceworker-same-origin";
-      let expected = {"destination":"serviceworker", "site":"same-origin"};
+      let expected = {"dest":"serviceworker", "site":"same-origin", "user":"?F"};
       fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
         .then(response => response.text())
         .then(text => assert_header_equals(text, expected))
diff --git a/fetch/sec-metadata/sharedworker.tentative.https.sub.html b/fetch/sec-metadata/sharedworker.tentative.https.sub.html
index 09017cc..66f7d5b 100644
--- a/fetch/sec-metadata/sharedworker.tentative.https.sub.html
+++ b/fetch/sec-metadata/sharedworker.tentative.https.sub.html
@@ -26,7 +26,7 @@
     promise_test(t => {
       return new Promise((resolve, reject) => {
         let key = "sharedworker-same-origin";
-        let expected = {"destination":"sharedworker", "site":"same-origin"};
+        let expected = {"dest":"sharedworker", "site":"same-origin", "user":"?F"};
 
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
diff --git a/fetch/sec-metadata/style.tentative.https.sub.html b/fetch/sec-metadata/style.tentative.https.sub.html
index 609d576..9697db7 100644
--- a/fetch/sec-metadata/style.tentative.https.sub.html
+++ b/fetch/sec-metadata/style.tentative.https.sub.html
@@ -14,7 +14,7 @@
       e.rel = "stylesheet";
       e.href = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
       e.onload = e => {
-        let expected = {"destination":"style", "site":"same-origin"};
+        let expected = {"dest":"style", "site":"same-origin", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
@@ -34,7 +34,7 @@
       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 = {"destination":"style", "site":"same-site"};
+        let expected = {"dest":"style", "site":"same-site", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
@@ -54,7 +54,7 @@
       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 = {"destination":"style", "site":"cross-site"};
+        let expected = {"dest":"style", "site":"cross-site", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
diff --git a/fetch/sec-metadata/track.tentative.https.sub.html b/fetch/sec-metadata/track.tentative.https.sub.html
index e89d474..b9dfabf 100644
--- a/fetch/sec-metadata/track.tentative.https.sub.html
+++ b/fetch/sec-metadata/track.tentative.https.sub.html
@@ -29,7 +29,7 @@
       let el = createTrack();
       el.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-same-origin";
       el.onload = t.step_func(_ => {
-        expected = {"destination":"track", "site":"same-origin"};
+        expected = {"dest":"track", "site":"same-origin", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-same-origin")
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
@@ -46,7 +46,7 @@
       let el = createTrack();
       el.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-same-site";
       el.onload = t.step_func(_ => {
-        expected = {"destination":"track", "site":"same-site"};
+        expected = {"dest":"track", "site":"same-site", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-same-site")
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
@@ -65,7 +65,7 @@
       let el = createTrack();
       el.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-cross-site";
       el.onload = t.step_func(_ => {
-        expected = {"destination":"track", "site":"cross-site"};
+        expected = {"dest":"track", "site":"cross-site", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-cross-site")
             .then(response => response.text())
             .then(text => assert_header_equals(text, expected))
diff --git a/fetch/sec-metadata/window-open.tentative.https.sub.html b/fetch/sec-metadata/window-open.tentative.https.sub.html
index 3cd6190..236268e 100644
--- a/fetch/sec-metadata/window-open.tentative.https.sub.html
+++ b/fetch/sec-metadata/window-open.tentative.https.sub.html
@@ -15,9 +15,9 @@
         return;
 
       assert_header_equals(e.data, {
-        "cause": "forced",
-        "destination": "document",
-        "site": "same-origin"
+        "dest": "document",
+        "site": "same-origin",
+        "user":"?F"
       });
       t.done();
     }));
@@ -31,9 +31,9 @@
         return;
 
       assert_header_equals(e.data, {
-        "cause": "forced",
-        "destination": "document",
-        "site": "same-site"
+        "dest": "document",
+        "site": "same-site",
+        "user":"?F"
       });
       t.done();
     }));
@@ -47,9 +47,9 @@
         return;
 
       assert_header_equals(e.data, {
-        "cause": "forced",
-        "destination": "document",
-        "site": "cross-site"
+        "dest": "document",
+        "site": "cross-site",
+        "user":"?F"
       });
       t.done();
     }));
@@ -66,9 +66,9 @@
           return;
 
         assert_header_equals(e.data, {
-          "cause": "user-activated",
-          "destination": "document",
-          "site": "same-origin"
+          "dest": "document",
+          "site": "same-origin",
+          "user": "?T"
         });
         t.done();
       }));
@@ -87,9 +87,9 @@
           return;
 
         assert_header_equals(e.data, {
-          "cause": "user-activated",
-          "destination": "document",
-          "site": "same-site"
+          "dest": "document",
+          "site": "same-site",
+          "user": "?T"
         });
         t.done();
       }));
@@ -108,9 +108,9 @@
           return;
 
         assert_header_equals(e.data, {
-          "cause": "user-activated",
-          "destination": "document",
-          "site": "cross-site"
+          "dest": "document",
+          "site": "cross-site",
+          "user": "?T"
         });
         t.done();
       }));
diff --git a/fetch/sec-metadata/worker.tentative.https.sub.html b/fetch/sec-metadata/worker.tentative.https.sub.html
index eff66fc..fcffe91 100644
--- a/fetch/sec-metadata/worker.tentative.https.sub.html
+++ b/fetch/sec-metadata/worker.tentative.https.sub.html
@@ -10,7 +10,7 @@
       let key = "worker-same-origin";
       let w = new Worker("/fetch/sec-metadata/resources/record-header.py?file=" + key);
       w.onmessage = e => {
-        let expected = {"destination":"worker", "site":"same-origin"};
+        let expected = {"dest":"worker", "site":"same-origin", "user":"?F"};
         fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
           .then(response => response.text())
           .then(text => assert_header_equals(text, expected))
diff --git a/fetch/sec-metadata/xslt.tentative.https.sub.html b/fetch/sec-metadata/xslt.tentative.https.sub.html
index dff9966..32349c9 100644
--- a/fetch/sec-metadata/xslt.tentative.https.sub.html
+++ b/fetch/sec-metadata/xslt.tentative.https.sub.html
@@ -12,21 +12,21 @@
       return;
 
     promise_test(t => {
-      let expected = {"destination":"xslt", "site":"same-origin"};
+      let expected = {"dest":"xslt", "site":"same-origin", "user":"?F"};
       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 = {"destination":"xslt", "site":"same-site"};
+      let expected = {"dest":"xslt", "site":"same-site", "user":"?F"};
       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 = {"destination":"xslt", "site":"cross-site"};
+      let expected = {"dest":"xslt", "site":"cross-site", "user":"?F"};
       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));