Commit bf5b0e09 authored by Josh Karlin's avatar Josh Karlin Committed by Commit Bot

[AdTracking] Include the top of the stack in AdTracker detection

Includes the script of the top stack frame in ads detection processing.

Bug: 807640
Change-Id: I8f4d0364ea088bf00abcc7310e4dccce7fec78f3
Reviewed-on: https://chromium-review.googlesource.com/986337
Commit-Queue: Josh Karlin <jkarlin@chromium.org>
Reviewed-by: default avatarNate Chapin <japhet@chromium.org>
Cr-Commit-Position: refs/heads/master@{#549509}
parent c63a0ba6
......@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/frame/AdTracker.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
#include "third_party/blink/renderer/core/CoreProbeSink.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
......@@ -27,6 +28,13 @@ void AdTracker::Shutdown() {
local_root_ = nullptr;
}
String AdTracker::ScriptAtTopOfStack(ExecutionContext* execution_context) {
std::unique_ptr<blink::SourceLocation> current_stack_trace =
SourceLocation::Capture(execution_context);
// TODO(jkarlin): Url() sometimes returns String(), why?
return current_stack_trace ? current_stack_trace->Url() : "";
}
void AdTracker::WillExecuteScript(const String& script_url) {
bool is_ad =
script_url.IsEmpty() ? false : known_ad_scripts_.Contains(script_url);
......@@ -76,22 +84,30 @@ void AdTracker::WillSendRequest(ExecutionContext* execution_context,
Resource::Type resource_type) {
// If the resource is not already marked as an ad, check if any executing
// script is an ad. If yes, mark this as an ad.
if (!request.IsAdResource() && AnyExecutingScriptsTaggedAsAdResource())
if (!request.IsAdResource() &&
AnyExecutingScriptsTaggedAsAdResource(execution_context))
request.SetIsAdResource();
// If it is a script marked as an ad, append it to the known ad scripts set.
if (resource_type != Resource::kScript || !request.IsAdResource()) {
return;
}
AppendToKnownAdScripts(request.Url());
if (resource_type == Resource::kScript && request.IsAdResource())
AppendToKnownAdScripts(request.Url());
}
// Keeping a separate function to easily access from tests.
// This is a separate function for testing purposes.
void AdTracker::AppendToKnownAdScripts(const KURL& url) {
known_ad_scripts_.insert(url.GetString());
}
bool AdTracker::AnyExecutingScriptsTaggedAsAdResource() {
bool AdTracker::AnyExecutingScriptsTaggedAsAdResource(
ExecutionContext* execution_context) {
// The pseudo-stack contains entry points into the stack (e.g., when v8 is
// executed) but not the entire stack. It's cheap to retrieve the top of the
// stack so scan that as well.
String top_script = ScriptAtTopOfStack(execution_context);
if (!top_script.IsEmpty() && known_ad_scripts_.Contains(top_script))
return true;
// Scan the pseudo-stack for ad scripts.
for (const auto& executing_script : executing_scripts_) {
if (executing_script.is_ad)
return true;
......
......@@ -27,8 +27,7 @@ class ExecuteScript;
// Tracker for tagging resources as ads based on the call stack scripts.
// The tracker is maintained per local root.
class CORE_EXPORT AdTracker final
: public GarbageCollectedFinalized<AdTracker> {
class CORE_EXPORT AdTracker : public GarbageCollectedFinalized<AdTracker> {
public:
// Instrumenting methods.
// Called when a script module or script gets executed from native code.
......@@ -56,7 +55,11 @@ class CORE_EXPORT AdTracker final
void Shutdown();
explicit AdTracker(LocalFrame*);
~AdTracker();
virtual ~AdTracker();
protected:
// Protected for testing.
virtual String ScriptAtTopOfStack(ExecutionContext*);
private:
friend class FrameFetchContextSubresourceFilterTest;
......@@ -69,7 +72,7 @@ class CORE_EXPORT AdTracker final
// Returns true if any script in the pseudo call stack has been identified as
// an ad earlier. An ad is identified as an ad if AppendToKnownAdScripts has
// been called on it earlier.
bool AnyExecutingScriptsTaggedAsAdResource();
bool AnyExecutingScriptsTaggedAsAdResource(ExecutionContext*);
Member<LocalFrame> local_root_;
......
......@@ -13,6 +13,27 @@
namespace blink {
namespace {
class TestAdTracker : public AdTracker {
public:
explicit TestAdTracker(LocalFrame* frame) : AdTracker(frame) {}
void SetScriptAtTopOfStack(String url) { script_at_top_ = url; }
~TestAdTracker() override {}
protected:
// Returns "" by default unless SetScriptAtTopOfStack is called with
// something else.
String ScriptAtTopOfStack(ExecutionContext* execution_context) override {
return script_at_top_;
}
private:
String script_at_top_;
};
} // namespace
class AdTrackerTest : public testing::Test {
protected:
void SetUp() override;
......@@ -26,21 +47,22 @@ class AdTrackerTest : public testing::Test {
}
bool AnyExecutingScriptsTaggedAsAdResource() {
return ad_tracker_->AnyExecutingScriptsTaggedAsAdResource();
return ad_tracker_->AnyExecutingScriptsTaggedAsAdResource(
&page_holder_->GetDocument());
}
void AppendToKnownAdScripts(const KURL& url) {
ad_tracker_->AppendToKnownAdScripts(url);
}
Persistent<AdTracker> ad_tracker_;
Persistent<TestAdTracker> ad_tracker_;
std::unique_ptr<DummyPageHolder> page_holder_;
};
void AdTrackerTest::SetUp() {
page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
page_holder_->GetDocument().SetURL(KURL("https://example.com/foo"));
ad_tracker_ = new AdTracker(GetFrame());
ad_tracker_ = new TestAdTracker(GetFrame());
}
void AdTrackerTest::TearDown() {
......@@ -64,4 +86,31 @@ TEST_F(AdTrackerTest, AnyExecutingScriptsTaggedAsAdResource_False) {
EXPECT_FALSE(AnyExecutingScriptsTaggedAsAdResource());
}
TEST_F(AdTrackerTest, TopOfStackIncluded) {
KURL ad_script_url("https://example.com/ad.js");
AppendToKnownAdScripts(ad_script_url);
WillExecuteScript("https://example.com/foo.js");
WillExecuteScript("https://example.com/bar.js");
EXPECT_FALSE(AnyExecutingScriptsTaggedAsAdResource());
ad_tracker_->SetScriptAtTopOfStack("https://www.example.com/baz.js");
EXPECT_FALSE(AnyExecutingScriptsTaggedAsAdResource());
ad_tracker_->SetScriptAtTopOfStack(ad_script_url);
EXPECT_TRUE(AnyExecutingScriptsTaggedAsAdResource());
ad_tracker_->SetScriptAtTopOfStack("https://www.example.com/baz.js");
EXPECT_FALSE(AnyExecutingScriptsTaggedAsAdResource());
ad_tracker_->SetScriptAtTopOfStack("");
EXPECT_FALSE(AnyExecutingScriptsTaggedAsAdResource());
ad_tracker_->SetScriptAtTopOfStack(WTF::String());
EXPECT_FALSE(AnyExecutingScriptsTaggedAsAdResource());
WillExecuteScript(ad_script_url);
EXPECT_TRUE(AnyExecutingScriptsTaggedAsAdResource());
}
} // namespace blink
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