Commit 4400d593 authored by Yao Xiao's avatar Yao Xiao Committed by Commit Bot

Log to ukm if a window.open() navigation is from an ad subframe and

if ad script is in stack.

Bug: 864160
Change-Id: I6ccac6ae44cfbb0d8bb98d8502b7f85da00479b3
Reviewed-on: https://chromium-review.googlesource.com/1176266
Commit-Queue: Yao Xiao <yaoxia@chromium.org>
Reviewed-by: default avatarNate Chapin <japhet@chromium.org>
Reviewed-by: default avatarRobert Kaplow (slow) <rkaplow@chromium.org>
Reviewed-by: default avatarCharlie Harrison <csharrison@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585018}
parent 071c57b8
...@@ -14,9 +14,12 @@ ...@@ -14,9 +14,12 @@
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h" #include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h"
#include "components/subresource_filter/core/common/test_ruleset_utils.h" #include "components/subresource_filter/core/common/test_ruleset_utils.h"
#include "components/ukm/content/source_url_recorder.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/test/browser_test.h" #include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_navigation_observer.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -111,14 +114,15 @@ content::RenderFrameHost* AdTaggingBrowserTest::CreateFrameImpl( ...@@ -111,14 +114,15 @@ content::RenderFrameHost* AdTaggingBrowserTest::CreateFrameImpl(
std::string script = base::StringPrintf( std::string script = base::StringPrintf(
"%s('%s','%s');", ad_script ? "createAdFrame" : "createFrame", "%s('%s','%s');", ad_script ? "createAdFrame" : "createFrame",
url.spec().c_str(), name.c_str()); url.spec().c_str(), name.c_str());
content::WebContents* web_contents =
content::TestNavigationObserver navigation_observer(GetWebContents(), 1); content::WebContents::FromRenderFrameHost(rfh);
content::TestNavigationObserver navigation_observer(web_contents, 1);
EXPECT_TRUE(content::ExecuteScript(rfh, script)); EXPECT_TRUE(content::ExecuteScript(rfh, script));
navigation_observer.Wait(); navigation_observer.Wait();
EXPECT_TRUE(navigation_observer.last_navigation_succeeded()) EXPECT_TRUE(navigation_observer.last_navigation_succeeded())
<< navigation_observer.last_net_error_code(); << navigation_observer.last_net_error_code();
return content::FrameMatchingPredicate( return content::FrameMatchingPredicate(
GetWebContents(), base::BindRepeating(&content::FrameMatchesName, name)); web_contents, base::BindRepeating(&content::FrameMatchesName, name));
} }
content::RenderFrameHost* AdTaggingBrowserTest::CreateDocWrittenFrameImpl( content::RenderFrameHost* AdTaggingBrowserTest::CreateDocWrittenFrameImpl(
...@@ -126,18 +130,19 @@ content::RenderFrameHost* AdTaggingBrowserTest::CreateDocWrittenFrameImpl( ...@@ -126,18 +130,19 @@ content::RenderFrameHost* AdTaggingBrowserTest::CreateDocWrittenFrameImpl(
bool ad_script) { bool ad_script) {
content::RenderFrameHost* rfh = adapter.render_frame_host(); content::RenderFrameHost* rfh = adapter.render_frame_host();
std::string name = GetUniqueFrameName(); std::string name = GetUniqueFrameName();
std::string script = base::StringPrintf( std::string script = base::StringPrintf(
"%s('%s', '%s');", "%s('%s', '%s');",
ad_script ? "createDocWrittenAdFrame" : "createDocWrittenFrame", ad_script ? "createDocWrittenAdFrame" : "createDocWrittenFrame",
name.c_str(), GetURL("").spec().c_str()); name.c_str(), GetURL("").spec().c_str());
content::TestNavigationObserver navigation_observer(GetWebContents(), 1); content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(rfh);
content::TestNavigationObserver navigation_observer(web_contents, 1);
EXPECT_TRUE(content::ExecuteScript(rfh, script)); EXPECT_TRUE(content::ExecuteScript(rfh, script));
navigation_observer.Wait(); navigation_observer.Wait();
EXPECT_TRUE(navigation_observer.last_navigation_succeeded()) EXPECT_TRUE(navigation_observer.last_navigation_succeeded())
<< navigation_observer.last_net_error_code(); << navigation_observer.last_net_error_code();
return content::FrameMatchingPredicate( return content::FrameMatchingPredicate(
GetWebContents(), base::BindRepeating(&content::FrameMatchesName, name)); web_contents, base::BindRepeating(&content::FrameMatchesName, name));
} }
// Given a RenderFrameHost, navigates the page to the given |url| and waits // Given a RenderFrameHost, navigates the page to the given |url| and waits
...@@ -320,6 +325,110 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, SameOriginFrameTagging) { ...@@ -320,6 +325,110 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, SameOriginFrameTagging) {
EXPECT_TRUE(*observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId())); EXPECT_TRUE(*observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId()));
} }
const ukm::mojom::UkmEntry* FindDocumentCreatedEntry(
const ukm::TestUkmRecorder& ukm_recorder,
ukm::SourceId source_id) {
auto entries =
ukm_recorder.GetEntriesByName(ukm::builders::DocumentCreated::kEntryName);
for (auto* entry : entries) {
if (entry->source_id == source_id)
return entry;
}
NOTREACHED();
return nullptr;
}
void ExpectLatestUkmEntry(const ukm::TestUkmRecorder& ukm_recorder,
size_t expected_num_entries,
base::StringPiece metric_name,
bool from_main_frame,
const GURL& main_frame_url,
int64_t expected_value) {
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::AbusiveExperienceHeuristic::kEntryName);
EXPECT_EQ(expected_num_entries, entries.size());
// Check that the event is keyed to |main_frame_url| only if it was from the
// top frame.
if (from_main_frame) {
ukm_recorder.ExpectEntrySourceHasUrl(entries.back(), main_frame_url);
} else {
EXPECT_FALSE(ukm_recorder.GetSourceForSourceId(entries.back()->source_id));
}
// Check that a DocumentCreated entry was created, and it's keyed to
// |main_frame_url| only if it was from the top frame. However, we can always
// use the navigation source ID to link this source to |main_frame_url|.
const ukm::mojom::UkmEntry* dc_entry =
FindDocumentCreatedEntry(ukm_recorder, entries.back()->source_id);
EXPECT_EQ(entries.back()->source_id, dc_entry->source_id);
if (from_main_frame) {
ukm_recorder.ExpectEntrySourceHasUrl(dc_entry, main_frame_url);
} else {
EXPECT_FALSE(ukm_recorder.GetSourceForSourceId(dc_entry->source_id));
}
const ukm::UkmSource* navigation_source =
ukm_recorder.GetSourceForSourceId(*ukm_recorder.GetEntryMetric(
dc_entry, ukm::builders::DocumentCreated::kNavigationSourceIdName));
EXPECT_EQ(main_frame_url, navigation_source->url());
EXPECT_EQ(from_main_frame,
*ukm_recorder.GetEntryMetric(
dc_entry, ukm::builders::DocumentCreated::kIsMainFrameName));
ukm_recorder.ExpectEntryMetric(entries.back(), metric_name, expected_value);
}
IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, WindowOpenFromSubframe) {
ukm::TestAutoSetUkmRecorder ukm_recorder;
GURL main_frame_url =
embedded_test_server()->GetURL("a.com", "/ad_tagging/frame_factory.html");
ui_test_utils::NavigateToURL(browser(), main_frame_url);
content::WebContents* main_tab = GetWebContents();
size_t expected_num_entries = 0;
for (bool cross_origin : {false, true}) {
for (bool ad_frame : {false, true}) {
std::string hostname = cross_origin ? "b.com" : "a.com";
std::string suffix = ad_frame ? "&ad=true" : "";
SCOPED_TRACE(::testing::Message()
<< "cross_origin = " << cross_origin << ", "
<< "ad_frame = " << ad_frame);
RenderFrameHost* child = CreateSrcFrame(
main_tab, embedded_test_server()->GetURL(
hostname, "/ad_tagging/frame_factory.html?1" + suffix));
EXPECT_TRUE(content::ExecuteScript(child, "window.open();"));
ExpectLatestUkmEntry(ukm_recorder, ++expected_num_entries,
ukm::builders::AbusiveExperienceHeuristic::
kDidWindowOpenFromAdSubframeName,
false /* from_main_frame */, main_frame_url,
ad_frame);
}
}
}
IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, WindowOpenWithScriptInStack) {
ukm::TestAutoSetUkmRecorder ukm_recorder;
GURL main_frame_url = GetURL("frame_factory.html");
ui_test_utils::NavigateToURL(browser(), main_frame_url);
content::WebContents* main_tab = GetWebContents();
EXPECT_TRUE(content::ExecuteScript(main_tab, "windowOpenFromNonAdScript();"));
ExpectLatestUkmEntry(
ukm_recorder, 1 /* expected_num_entries */,
ukm::builders::AbusiveExperienceHeuristic::kDidWindowOpenFromAdScriptName,
true /* from_main_frame */, main_frame_url, false /* expected_value */);
EXPECT_TRUE(content::ExecuteScript(main_tab, "windowOpenFromAdScript();"));
ExpectLatestUkmEntry(
ukm_recorder, 2 /* expected_num_entries */,
ukm::builders::AbusiveExperienceHeuristic::kDidWindowOpenFromAdScriptName,
true /* from_main_frame */, main_frame_url, true /* expected_value */);
}
} // namespace } // namespace
} // namespace subresource_filter } // namespace subresource_filter
...@@ -7,6 +7,10 @@ function createAdFrame(url, name) { ...@@ -7,6 +7,10 @@ function createAdFrame(url, name) {
document.body.appendChild(frame); document.body.appendChild(frame);
} }
function windowOpenFromAdScript() {
window.open();
}
async function createDocWrittenAdFrame(name, base_url) { async function createDocWrittenAdFrame(name, base_url) {
let doc_body = await fetch('frame_factory.html'); let doc_body = await fetch('frame_factory.html');
let doc_text = await doc_body.text(); let doc_text = await doc_body.text();
......
...@@ -7,6 +7,10 @@ function createFrame(url, name) { ...@@ -7,6 +7,10 @@ function createFrame(url, name) {
document.body.appendChild(frame); document.body.appendChild(frame);
} }
function windowOpenFromNonAdScript() {
window.open();
}
async function createDocWrittenFrame(name, base_url) { async function createDocWrittenFrame(name, base_url) {
let doc_body = await fetch('frame_factory.html'); let doc_body = await fetch('frame_factory.html');
let doc_text = await doc_body.text(); let doc_text = await doc_body.text();
......
...@@ -26,12 +26,14 @@ ...@@ -26,12 +26,14 @@
#include "third_party/blink/renderer/core/page/create_window.h" #include "third_party/blink/renderer/core/page/create_window.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/network/public/mojom/request_context_frame_type.mojom-blink.h" #include "services/network/public/mojom/request_context_frame_type.mojom-blink.h"
#include "third_party/blink/public/platform/web_input_event.h" #include "third_party/blink/public/platform/web_input_event.h"
#include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/web/web_window_features.h" #include "third_party/blink/public/web/web_window_features.h"
#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h" #include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/ad_tracker.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h" #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/frame_client.h" #include "third_party/blink/renderer/core/frame/frame_client.h"
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
...@@ -195,6 +197,24 @@ static Frame* ReuseExistingWindow(LocalFrame& active_frame, ...@@ -195,6 +197,24 @@ static Frame* ReuseExistingWindow(LocalFrame& active_frame,
return nullptr; return nullptr;
} }
static void MaybeLogWindowOpenUKM(LocalFrame& opener_frame) {
AdTracker* ad_tracker = opener_frame.GetAdTracker();
if (!ad_tracker) {
return;
}
ukm::UkmRecorder* ukm_recorder = opener_frame.GetDocument()->UkmRecorder();
ukm::SourceId source_id = opener_frame.GetDocument()->UkmSourceID();
bool is_ad_subframe = opener_frame.IsAdSubframe();
bool is_ad_script_in_stack = ad_tracker->IsAdScriptInStack();
if (source_id != ukm::kInvalidSourceId) {
ukm::builders::AbusiveExperienceHeuristic(source_id)
.SetDidWindowOpenFromAdSubframe(is_ad_subframe)
.SetDidWindowOpenFromAdScript(is_ad_script_in_stack)
.Record(ukm_recorder);
}
}
static Frame* CreateNewWindow(LocalFrame& opener_frame, static Frame* CreateNewWindow(LocalFrame& opener_frame,
const FrameLoadRequest& request, const FrameLoadRequest& request,
const WebWindowFeatures& features, const WebWindowFeatures& features,
...@@ -256,6 +276,7 @@ static Frame* CreateNewWindow(LocalFrame& opener_frame, ...@@ -256,6 +276,7 @@ static Frame* CreateNewWindow(LocalFrame& opener_frame,
page->GetChromeClient().SetWindowRectWithAdjustment(window_rect, frame); page->GetChromeClient().SetWindowRectWithAdjustment(window_rect, frame);
page->GetChromeClient().Show(policy); page->GetChromeClient().Show(policy);
MaybeLogWindowOpenUKM(opener_frame);
created = true; created = true;
return &frame; return &frame;
} }
......
...@@ -19,6 +19,8 @@ be describing additional metrics about the same event. ...@@ -19,6 +19,8 @@ be describing additional metrics about the same event.
<ukm-configuration> <ukm-configuration>
<event name="AbusiveExperienceHeuristic"> <event name="AbusiveExperienceHeuristic">
<owner>csharrison@chromium.org</owner>
<owner>yaoxia@chromium.org</owner>
<summary> <summary>
Various metrics recording experiences which are commonly used for abusive Various metrics recording experiences which are commonly used for abusive
purposes. purposes.
...@@ -28,6 +30,16 @@ be describing additional metrics about the same event. ...@@ -28,6 +30,16 @@ be describing additional metrics about the same event.
True if the page attempted a tab-under navigation. True if the page attempted a tab-under navigation.
</summary> </summary>
</metric> </metric>
<metric name="DidWindowOpenFromAdScript">
<summary>
True if the page called window.open with an ad script in the stack.
</summary>
</metric>
<metric name="DidWindowOpenFromAdSubframe">
<summary>
True if the page called window.open() from an ad subframe.
</summary>
</metric>
</event> </event>
<event name="Autofill.CardUploadDecision"> <event name="Autofill.CardUploadDecision">
......
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