Commit 0583f458 authored by Yifan Luo's avatar Yifan Luo Committed by Commit Bot

Fetch Metadata: split up `document` destination.

As discussed in
https://github.com/w3c/webappsec-fetch-metadata/issues/45,

We have decided to shift the model around nested navigations from
exposure via the request's `mode` to its `destination`. This patch
splits the existing `document` destination into three parts:
 - `document` for top-level navigations and, for the moment, <portals>.
 - `iframe` for <iframe> navigations.
 - `frame` for <frame> navigations.

Subsequent patch will remove the `nested-document` mode when we're ready
to ship `Sec-Fetch-Dest`.

Bug: 1011724
Change-Id: I23f23922fb49523aa050f59cbf13aabc086600bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1847295Reviewed-by: default avatarArthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: default avatarMike West <mkwst@chromium.org>
Commit-Queue: Yifan Luo <lyf@google.com>
Cr-Commit-Position: refs/heads/master@{#705527}
parent 2b601827
......@@ -305,12 +305,18 @@ void AddAdditionalRequestHeaders(net::HttpRequestHeaders* headers,
destination = "embed";
break;
case blink::FrameOwnerElementType::kIframe:
destination = "iframe";
break;
case blink::FrameOwnerElementType::kFrame:
destination = "frame";
break;
case blink::FrameOwnerElementType::kPortal:
// TODO(mkwst): "Portal"'s destination isn't actually defined at the
// moment. Let's assume it'll be similar to a frame until we decide
// otherwise.
destination = "nested-document";
// https://github.com/w3c/webappsec-fetch-metadata/issues/46
destination = "document";
break;
}
if (IsFetchMetadataDestinationEnabled()) {
......
......@@ -28,8 +28,10 @@ const char* GetRequestDestinationFromContext(
case mojom::RequestContextType::FONT:
return "font";
case mojom::RequestContextType::FRAME:
case mojom::RequestContextType::HYPERLINK:
return "frame";
case mojom::RequestContextType::IFRAME:
return "iframe";
case mojom::RequestContextType::HYPERLINK:
case mojom::RequestContextType::LOCATION:
case mojom::RequestContextType::FORM:
return "document";
......
......@@ -353,7 +353,9 @@ void SetSecFetchHeaders(
destination_value = "empty";
// We'll handle adding these headers to navigations outside of Blink.
if (strncmp(destination_value, "document", 8) != 0 &&
if ((strncmp(destination_value, "document", 8) != 0 ||
strncmp(destination_value, "iframe", 6) != 0 ||
strncmp(destination_value, "frame", 5) != 0) &&
request.GetRequestContext() != mojom::RequestContextType::INTERNAL) {
if (blink::RuntimeEnabledFeatures::FetchMetadataDestinationEnabled()) {
request.SetHttpHeaderField("Sec-Fetch-Dest", destination_value);
......
<!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/metadata/resources/helper.js></script>
<script src=/common/utils.js></script>
<body>
<script>
const USER = true;
const FORCED = false;
function create_test(host, user_activated, expectations) {
async_test(t => {
let i = document.createElement('frame');
window.addEventListener('message', t.step_func(e => {
if (e.source != i.contentWindow)
return;
assert_header_dest_equals(e.data, expectations);
t.done();
}));
let url = `https://${host}/fetch/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);
document.body.appendChild(a);
test_driver.click(a);
}
}, `{{host}} -> ${host} iframe: ${user_activated ? "user-activated" : "forced"}`);
}
create_test("{{host}}:{{ports[https][0]}}", FORCED, "frame");
create_test("{{hosts[][www]}}:{{ports[https][0]}}", FORCED, "frame");
create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", FORCED, "frame");
create_test("{{host}}:{{ports[https][0]}}", USER, "frame");
create_test("{{hosts[][www]}}:{{ports[https][0]}}", USER, "frame");
create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", USER, "frame");
</script>
<!DOCTYPE html>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/fetch/metadata/resources/helper.js></script>
<body>
<script>
async_test(t => {
let i = document.createElement('frame');
i.src = "http://{{host}}:{{ports[http][0]}}/fetch/metadata/resources/post-to-owner.py";
window.addEventListener('message', t.step_func(e => {
if (e.source != i.contentWindow)
return;
assert_header_dest_equals(e.data, "");
t.done();
}));
document.body.appendChild(i);
}, "Non-secure same-origin iframe => No headers");
async_test(t => {
let i = document.createElement('frame');
i.src = "http://{{hosts[][www]}}:{{ports[http][0]}}/fetch/metadata/resources/post-to-owner.py";
window.addEventListener('message', t.step_func(e => {
if (e.source != i.contentWindow)
return;
assert_header_dest_equals(e.data, "");
t.done();
}));
document.body.appendChild(i);
}, "Non-secure same-site iframe => No headers");
async_test(t => {
let i = document.createElement('frame');
i.src = "http://{{hosts[alt][www]}}:{{ports[http][0]}}/fetch/metadata/resources/post-to-owner.py";
window.addEventListener('message', t.step_func(e => {
if (e.source != i.contentWindow)
return;
assert_header_dest_equals(e.data, "");
t.done();
}));
document.body.appendChild(i);
}, "Non-secure cross-site iframe => No headers.");
async_test(t => {
let i = document.createElement('frame');
i.src = "https://{{host}}:{{ports[https][0]}}/fetch/metadata/resources/post-to-owner.py";
window.addEventListener('message', t.step_func(e => {
if (e.source != i.contentWindow)
return;
assert_header_dest_equals(e.data, "frame");
t.done();
}));
document.body.appendChild(i);
}, "Secure, cross-site (cross-scheme, same-host) frame");
</script>
......@@ -41,15 +41,15 @@
}, `{{host}} -> ${host} iframe: ${user_activated ? "user-activated" : "forced"}`);
}
create_test("{{host}}:{{ports[https][0]}}", FORCED, "nested-document");
create_test("{{host}}:{{ports[https][0]}}", FORCED, "iframe");
create_test("{{hosts[][www]}}:{{ports[https][0]}}", FORCED, "nested-document");
create_test("{{hosts[][www]}}:{{ports[https][0]}}", FORCED, "iframe");
create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", FORCED, "nested-document");
create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", FORCED, "iframe");
create_test("{{host}}:{{ports[https][0]}}", USER, "nested-document");
create_test("{{host}}:{{ports[https][0]}}", USER, "iframe");
create_test("{{hosts[][www]}}:{{ports[https][0]}}", USER, "nested-document");
create_test("{{hosts[][www]}}:{{ports[https][0]}}", USER, "iframe");
create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", USER, "nested-document");
create_test("{{hosts[alt][www]}}:{{ports[https][0]}}", USER, "iframe");
</script>
......@@ -53,7 +53,7 @@
if (e.source != i.contentWindow)
return;
assert_header_dest_equals(e.data, "nested-document");
assert_header_dest_equals(e.data, "iframe");
t.done();
}));
......
......@@ -14,7 +14,7 @@ Http headers:
HTTP_CONNECTION = keep-alive
HTTP_HOST = localhost:8080
HTTP_REFERER = http://127.0.0.1:8000/navigation/form-targets-cross-site-frame-get.html
HTTP_SEC_FETCH_DEST = nested-document
HTTP_SEC_FETCH_DEST = iframe
HTTP_SEC_FETCH_MODE = nested-navigate
HTTP_SEC_FETCH_SITE = cross-site
HTTP_UPGRADE_INSECURE_REQUESTS = 1
......@@ -15,7 +15,7 @@ HTTP_CACHE_CONTROL = max-age=0
HTTP_CONNECTION = keep-alive
HTTP_HOST = localhost:8080
HTTP_ORIGIN = null
HTTP_SEC_FETCH_DEST = nested-document
HTTP_SEC_FETCH_DEST = iframe
HTTP_SEC_FETCH_MODE = nested-navigate
HTTP_SEC_FETCH_SITE = cross-site
HTTP_UPGRADE_INSECURE_REQUESTS = 1
......@@ -16,7 +16,7 @@ HTTP_CONNECTION = keep-alive
HTTP_HOST = localhost:8080
HTTP_ORIGIN = http://127.0.0.1:8000
HTTP_REFERER = http://127.0.0.1:8000/navigation/form-targets-cross-site-frame-post.html
HTTP_SEC_FETCH_DEST = nested-document
HTTP_SEC_FETCH_DEST = iframe
HTTP_SEC_FETCH_MODE = nested-navigate
HTTP_SEC_FETCH_SITE = cross-site
HTTP_UPGRADE_INSECURE_REQUESTS = 1
......@@ -16,7 +16,7 @@ HTTP_CONNECTION = keep-alive
HTTP_HOST = localhost:8080
HTTP_ORIGIN = http://127.0.0.1:8000
HTTP_REFERER = http://127.0.0.1:8000/navigation/form-with-enctype-targets-cross-site-frame.html
HTTP_SEC_FETCH_DEST = nested-document
HTTP_SEC_FETCH_DEST = iframe
HTTP_SEC_FETCH_MODE = nested-navigate
HTTP_SEC_FETCH_SITE = cross-site
HTTP_UPGRADE_INSECURE_REQUESTS = 1
......@@ -17,7 +17,7 @@ HTTP_CONNECTION = keep-alive
HTTP_HOST = 127.0.0.1:8000
HTTP_ORIGIN = http://127.0.0.1:8000
HTTP_REFERER = http://127.0.0.1:8000/navigation/resources/page-that-posts.html
HTTP_SEC_FETCH_DEST = nested-document
HTTP_SEC_FETCH_DEST = iframe
HTTP_SEC_FETCH_MODE = nested-navigate
HTTP_SEC_FETCH_SITE = same-origin
HTTP_UPGRADE_INSECURE_REQUESTS = 1
......
......@@ -16,7 +16,7 @@ HTTP_CONNECTION = keep-alive
HTTP_HOST = 127.0.0.1:8000
HTTP_ORIGIN = http://127.0.0.1:8000
HTTP_REFERER = http://127.0.0.1:8000/navigation/post-frames-goback1.html
HTTP_SEC_FETCH_DEST = nested-document
HTTP_SEC_FETCH_DEST = iframe
HTTP_SEC_FETCH_MODE = nested-navigate
HTTP_SEC_FETCH_SITE = same-origin
HTTP_UPGRADE_INSECURE_REQUESTS = 1
......
......@@ -20,7 +20,7 @@ HTTP_CONNECTION = keep-alive
HTTP_HOST = 127.0.0.1:8000
HTTP_ORIGIN = http://127.0.0.1:8000
HTTP_REFERER = http://127.0.0.1:8000/navigation/resources/page-that-posts.html
HTTP_SEC_FETCH_DEST = nested-document
HTTP_SEC_FETCH_DEST = iframe
HTTP_SEC_FETCH_MODE = nested-navigate
HTTP_SEC_FETCH_SITE = same-origin
HTTP_UPGRADE_INSECURE_REQUESTS = 1
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment