Skip to content

Commit

Permalink
Fenced Frames: Temporarily allow window.fence.reportEvent from iframe…
Browse files Browse the repository at this point in the history
…s cherrypick into M104

Associated with the FLEDGE origin trial, there is a flag that allows iframes to load urn:uuids. This CL also enables window.fence.reportEvent in that case, to make it easier to test the new APIs. This will be removed when the iframe urn:uuid flag is removed.

For implementation reasons, the behavior right now is:
- If the invoking frame is in a fenced frame tree, the behavior is the same as before.
- If the invoking frame isn't in a fenced frame tree, reportEvent is available only when the invoking frame is an iframe whose document was navigated to a urn:uuid with attached reporting metadata.

For some examples:

* embedder > iframe1 (urn1) > iframe2 (https)
  fence.reportEvent works from iframe1 only.
* embedder > iframe1 (urn1) > iframe2 (urn2)
  fence.reportEvent works from iframe1 (to urn1) and iframe2 (to urn2)
* embedder > fencedframe1 (urn1) > iframe2 (https)
  fence.reportEvent works from fencedframe1 and iframe2 (both to urn1)
* embedder > fencedframe1 (urn1) > iframe2 (urn2)
  fence.reportEvent works from fencedframe1 and iframe2 (BOTH to urn1)

WICG/turtledove#309

(cherry picked from commit 95b0232)

Change-Id: Ie85bfb5264eb1ae78769533b2b8939f3168c8656
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3690741
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Arthur Sonzogni <[email protected]>
Reviewed-by: Shivani Sharma <[email protected]>
Commit-Queue: Garrett Tanzer <[email protected]>
Cr-Original-Commit-Position: refs/heads/main@{#1014688}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3721476
Bot-Commit: Rubber Stamper <[email protected]>
Cr-Commit-Position: refs/branch-heads/5112@{chromium#262}
Cr-Branched-From: b13d3fe-refs/heads/main@{#1012729}
  • Loading branch information
Garrett Tanzer authored and Chromium LUCI CQ committed Jun 24, 2022
1 parent f2d338d commit f738dd6
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 25 deletions.
113 changes: 97 additions & 16 deletions content/browser/renderer_host/frame_tree_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,7 @@ IN_PROC_BROWSER_TEST_P(FencedFrameTreeBrowserTest,
GURL urn_uuid = url_mapping.AddFencedFrameURL(https_url);
EXPECT_TRUE(urn_uuid.is_valid());

std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);

{
TestFrameNavigationObserver observer(fenced_frame_root_node);
Expand Down Expand Up @@ -1136,17 +1136,15 @@ IN_PROC_BROWSER_TEST_P(
{
TestFrameNavigationObserver observer(
fenced_frame_root_node1->current_frame_host());
std::string navigate_urn_script =
JsReplace("f1.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f1.src = $1;", urn_uuid);
EXPECT_EQ(urn_uuid.spec(), EvalJs(root, navigate_urn_script));
observer.Wait();
}

{
TestFrameNavigationObserver observer(
fenced_frame_root_node2->current_frame_host());
std::string navigate_urn_script =
JsReplace("f2.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f2.src = $1;", urn_uuid);
EXPECT_EQ(urn_uuid.spec(), EvalJs(root, navigate_urn_script));
observer.Wait();
}
Expand Down Expand Up @@ -1188,7 +1186,7 @@ IN_PROC_BROWSER_TEST_P(
const GURL urn_uuid = url_mapping.GeneratePendingMappedURN();
const GURL mapped_url =
https_server()->GetURL("a.test", "/fenced_frames/title1.html");
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);

TestFrameNavigationObserver observer(
fenced_frame_root_node->current_frame_host());
Expand Down Expand Up @@ -1266,7 +1264,7 @@ IN_PROC_BROWSER_TEST_P(
const GURL urn_uuid = url_mapping.GeneratePendingMappedURN();
const GURL mapped_url =
https_server()->GetURL("a.test", "/fenced_frames/nonexistent-url.html");
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);

TestFrameNavigationObserver observer(
fenced_frame_root_node->current_frame_host());
Expand Down Expand Up @@ -1334,7 +1332,7 @@ IN_PROC_BROWSER_TEST_P(
const GURL urn_uuid = url_mapping.GeneratePendingMappedURN();
const GURL mapped_url =
https_server()->GetURL("a.test", "/fenced_frames/title1.html");
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);

TestFrameNavigationObserver observer(
fenced_frame_root_node->current_frame_host());
Expand Down Expand Up @@ -1412,7 +1410,7 @@ IN_PROC_BROWSER_TEST_P(FencedFrameTreeBrowserTest,
GURL urn_uuid = url_mapping.AddFencedFrameURL(https_url);
EXPECT_TRUE(urn_uuid.is_valid());

std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);
NavigateFrameInsideFencedFrameTreeAndWaitForFinishedLoad(
fenced_frame_root_node, urn_uuid, navigate_urn_script);
EXPECT_EQ(
Expand Down Expand Up @@ -1494,7 +1492,7 @@ IN_PROC_BROWSER_TEST_P(FencedFrameTreeBrowserTest,
GURL urn_uuid = url_mapping.AddFencedFrameURL(https_url);
EXPECT_TRUE(urn_uuid.is_valid());

std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);
NavigateFrameInsideFencedFrameTreeAndWaitForFinishedLoad(
fenced_frame_root_node, urn_uuid, navigate_urn_script);
EXPECT_EQ(
Expand Down Expand Up @@ -1833,7 +1831,7 @@ IN_PROC_BROWSER_TEST_P(FencedFrameTreeBrowserTest,
GURL urn_uuid = url_mapping.AddFencedFrameURL(https_url);
EXPECT_TRUE(urn_uuid.is_valid());

std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);
NavigateFrameInsideFencedFrameTreeAndWaitForFinishedLoad(
fenced_frame_root_node, urn_uuid, navigate_urn_script,
net::ERR_BLOCKED_BY_RESPONSE);
Expand Down Expand Up @@ -2799,7 +2797,7 @@ IN_PROC_BROWSER_TEST_P(FencedFrameTreeBrowserTest, CheckInvalidUrnError) {
GURL urn_uuid = GURL("urn:uuid:12345678-9abc-def0-1234-56789abcdef0");
EXPECT_TRUE(urn_uuid.is_valid());

std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);
NavigateFrameInsideFencedFrameTreeAndWaitForFinishedLoad(
fenced_frame_root_node, urn_uuid, navigate_urn_script, InvalidUrnError());
}
Expand Down Expand Up @@ -2860,7 +2858,7 @@ IN_PROC_BROWSER_TEST_P(FencedFrameTreeBrowserTest,
GURL urn_uuid = url_mapping.AddFencedFrameURL(https_url);
EXPECT_TRUE(urn_uuid.is_valid());

std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);

net::Error expected_net_error_code =
test_case.expect_allowed ? net::OK : net::ERR_BLOCKED_BY_CSP;
Expand Down Expand Up @@ -3331,6 +3329,14 @@ INSTANTIATE_TEST_SUITE_P(

class FencedFrameReportEventBrowserTest : public FencedFrameTreeBrowserTest {
public:
// TODO(crbug.com/1123606): Disable window.fence.reportEvent in iframes.
// Remove this constructor and `scoped_feature_list_` once FLEDGE stops
// supporting iframes.
FencedFrameReportEventBrowserTest() {
scoped_feature_list_.InitWithFeaturesAndParameters(
{{blink::features::kAllowURNsInIframes, {}}},
{/* disabled_features */});
}
void SetUpOnMainThread() override {
// Set up the host resolver to allow serving separate sites, so we can
// perform cross-process navigation.
Expand All @@ -3344,6 +3350,9 @@ class FencedFrameReportEventBrowserTest : public FencedFrameTreeBrowserTest {
https_server()->ServeFilesFromSourceDirectory(GetTestDataFilePath());
https_server()->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
}

private:
base::test::ScopedFeatureList scoped_feature_list_;
};

// Tests that the fenced frame with a urn:uuid commits the navigation with the
Expand Down Expand Up @@ -3390,12 +3399,13 @@ IN_PROC_BROWSER_TEST_P(FencedFrameReportEventBrowserTest,
url_mapping.AddFencedFrameURL(https_url, fenced_frame_reporting);
EXPECT_TRUE(urn_uuid.is_valid());

std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());

TestFencedFrameURLMappingResultObserver mapping_observer;
url_mapping.ConvertFencedFrameURNToURL(urn_uuid, &mapping_observer);
TestFrameNavigationObserver observer(fenced_frame_root_node);

std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);
EXPECT_EQ(urn_uuid.spec(), EvalJs(root, navigate_urn_script));

observer.WaitForCommit();
EXPECT_TRUE(mapping_observer.mapping_complete_observed());
EXPECT_EQ(reporting_url,
Expand All @@ -3422,6 +3432,77 @@ IN_PROC_BROWSER_TEST_P(FencedFrameReportEventBrowserTest,
EXPECT_EQ(response.http_request()->content, event_data);
}

// (Temporary test for FLEDGE iframe OT.)
// Tests that an iframe with a urn:uuid commits the navigation with the
// associated reporting metadata and `fence.reportEvent` sends the beacon to
// the registered reporting url.
// TODO(crbug.com/1123606): Disable window.fence.reportEvent in iframes.
// Remove this test once the FLEDGE origin trial stops supporting iframes.
IN_PROC_BROWSER_TEST_P(FencedFrameReportEventBrowserTest,
IframeReportingMetadata) {
net::test_server::ControllableHttpResponse response(https_server(),
"/title2.html");
ASSERT_TRUE(https_server()->Start());

GURL main_url = https_server()->GetURL("b.test", "/hello.html");
EXPECT_TRUE(NavigateToURL(shell(), main_url));
// It is safe to obtain the root frame tree node here, as it doesn't change.
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();

EXPECT_TRUE(ExecJs(root,
"var f = document.createElement('iframe');"
"document.body.appendChild(f);"));
EXPECT_EQ(1U, root->child_count());
FrameTreeNode* iframe_node = root->child_at(0);

// Add reporting metadata.
ReportingMetadata fenced_frame_reporting;
GURL reporting_url(https_server()->GetURL("c.test", "/title2.html"));
fenced_frame_reporting.metadata[blink::mojom::ReportingDestination::kBuyer]
["mouse interaction"] = reporting_url;
fenced_frame_reporting
.metadata[blink::mojom::ReportingDestination::kBuyer]["click"] =
https_server()->GetURL("c.test", "/title1.html");

GURL https_url(
https_server()->GetURL("a.test", "/fenced_frames/title1.html"));
FencedFrameURLMapping& url_mapping =
root->current_frame_host()->GetPage().fenced_frame_urls_map();
GURL urn_uuid =
url_mapping.AddFencedFrameURL(https_url, fenced_frame_reporting);
EXPECT_TRUE(urn_uuid.is_valid());

TestFencedFrameURLMappingResultObserver mapping_observer;
url_mapping.ConvertFencedFrameURNToURL(urn_uuid, &mapping_observer);
TestFrameNavigationObserver observer(iframe_node);

EXPECT_EQ(urn_uuid.spec(), EvalJs(root, JsReplace("f.src = $1;", urn_uuid)));

observer.WaitForCommit();
EXPECT_TRUE(mapping_observer.mapping_complete_observed());
EXPECT_EQ(reporting_url,
mapping_observer.reporting_metadata()
.metadata[blink::mojom::ReportingDestination::kBuyer]
["mouse interaction"]);

EXPECT_EQ(https_url,
iframe_node->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(https_url),
iframe_node->current_frame_host()->GetLastCommittedOrigin());

std::string event_data = "this is a click";
EXPECT_TRUE(ExecJs(iframe_node, JsReplace("window.fence.reportEvent({"
" eventType: 'mouse interaction',"
" eventData: $1,"
" destination: ['buyer']});",
event_data)));

response.WaitForRequest();
EXPECT_EQ(response.http_request()->content, event_data);
}

IN_PROC_BROWSER_TEST_P(FencedFrameReportEventBrowserTest,
NestedIframeReportEvent) {
net::test_server::ControllableHttpResponse response(https_server(),
Expand Down Expand Up @@ -3461,7 +3542,7 @@ IN_PROC_BROWSER_TEST_P(FencedFrameReportEventBrowserTest,
EXPECT_TRUE(urn_uuid.is_valid());

// Navigate the fenced frame.
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid.spec());
std::string navigate_urn_script = JsReplace("f.src = $1;", urn_uuid);
NavigateFrameInsideFencedFrameTreeAndWaitForFinishedLoad(
fenced_frame_root_node, urn_uuid, navigate_urn_script);

Expand Down
11 changes: 10 additions & 1 deletion third_party/blink/renderer/core/frame/local_dom_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2314,9 +2314,18 @@ void LocalDOMWindow::DidBufferLoadWhileInBackForwardCache(size_t num_bytes) {

Fence* LocalDOMWindow::fence() {
// Return nullptr if we aren't in a fenced subtree.
if (!GetFrame() || !GetFrame()->IsInFencedFrameTree()) {
if (!GetFrame()) {
return nullptr;
}
if (!GetFrame()->IsInFencedFrameTree()) {
// We temporarily allow window.fence in iframes with fenced frame reporting
// metadata (navigated by urn:uuids).
// If we are in an iframe that doesn't qualify, return nullptr.
if (!blink::features::IsAllowURNsInIframeEnabled() ||
!GetFrame()->GetDocument()->Loader()->FencedFrameReporting()) {
return nullptr;
}
}

if (!fence_) {
fence_ = MakeGarbageCollected<Fence>(*this);
Expand Down
34 changes: 26 additions & 8 deletions third_party/blink/renderer/core/html/fenced_frame/fence.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/html/fenced_frame/fence.h"

#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/frame/frame_policy.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink.h"
#include "third_party/blink/public/mojom/fenced_frame/fenced_frame.mojom-blink.h"
Expand Down Expand Up @@ -58,17 +59,34 @@ void Fence::reportEvent(ScriptState* script_state,

LocalFrame* frame = DomWindow()->GetFrame();
DCHECK(frame);
DCHECK(frame->IsInFencedFrameTree());

if (frame->GetFencedFrameMode() !=
mojom::blink::FencedFrameMode::kOpaqueAds) {
AddConsoleMessage(
"fence.reportEvent is only available in the 'opaque-ads' mode.");
return;
LocalFrame* fenced_frame = nullptr;
if (blink::features::IsAllowURNsInIframeEnabled() &&
!frame->IsInFencedFrameTree()) {
// The only way to get a Fence outside a fenced frame is from
// LocalDOMWindow::fence(), when both:
// - blink::features::IsAllowURNsInIframeEnabled() is true
// - the Document itself was loaded from a urn:uuid
// In that case, pretend that the frame is a fenced frame root for this
// temporary experiment.
// TODO(crbug.com/1123606): Disable window.fence.reportEvent in iframes.
// In order to disable, run the else branch unconditionally.
// Also remove the features.h include above.
fenced_frame = frame;
} else {
DCHECK(frame->IsInFencedFrameTree());

if (frame->GetFencedFrameMode() !=
mojom::blink::FencedFrameMode::kOpaqueAds) {
AddConsoleMessage(
"fence.reportEvent is only available in the 'opaque-ads' mode.");
return;
}

fenced_frame = DynamicTo<LocalFrame>(
DomWindow()->GetFrame()->Top(FrameTreeBoundary::kFenced));
}

LocalFrame* fenced_frame = DynamicTo<LocalFrame>(
DomWindow()->GetFrame()->Top(FrameTreeBoundary::kFenced));
DCHECK(fenced_frame);
DCHECK(fenced_frame->GetDocument());

Expand Down

0 comments on commit f738dd6

Please sign in to comment.