Commit 83609dcb authored by Josh Karlin's avatar Josh Karlin Committed by Commit Bot

[AdTracking] Tag local subframes as ads if ad script is in stack on creation

If the AdTracker sees an ad script in the stack when a frame is created,
or its parent frame is thought to be an ad, label the LocalFrame as an
ad frame. The subresource filter will then label subsequent requests in
that frame as ad requests.

A future CL will handle situations where the frame changes processes.

Bug: 807640
Change-Id: Ie4d3bab747c3158d310652f6376cc79f6da38b7a
Reviewed-on: https://chromium-review.googlesource.com/1019743
Commit-Queue: Josh Karlin <jkarlin@chromium.org>
Reviewed-by: default avatarNate Chapin <japhet@chromium.org>
Reviewed-by: default avatarCharlie Harrison <csharrison@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553845}
parent 5e5291a8
......@@ -742,6 +742,12 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
true /* is_ad_subframe */);
}
TEST_P(ContentSubresourceFilterThrottleManagerTest,
DryRun_FrameTaggingDeleted) {
NavigateAndCommitMainFrame(GURL(kTestURLWithDryRun));
ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
}
TEST_P(ContentSubresourceFilterThrottleManagerTest,
DryRun_FrameTaggingAsAdPropagatesToChildFrame) {
NavigateAndCommitMainFrame(GURL(kTestURLWithDryRun));
......
......@@ -37,8 +37,7 @@ SubresourceFilterAgent::SubresourceFilterAgent(
UnverifiedRulesetDealer* ruleset_dealer)
: content::RenderFrameObserver(render_frame),
content::RenderFrameObserverTracker<SubresourceFilterAgent>(render_frame),
ruleset_dealer_(ruleset_dealer),
is_ad_subframe_for_next_commit_(false) {
ruleset_dealer_(ruleset_dealer) {
DCHECK(ruleset_dealer);
}
......@@ -70,6 +69,14 @@ void SubresourceFilterAgent::SendDocumentLoadStatistics(
render_frame()->GetRoutingID(), statistics));
}
bool SubresourceFilterAgent::IsAdSubframe() {
return render_frame()->GetWebFrame()->IsAdSubframe();
}
void SubresourceFilterAgent::SetIsAdSubframe() {
render_frame()->GetWebFrame()->SetIsAdSubframe();
}
// static
ActivationState SubresourceFilterAgent::GetParentActivationState(
content::RenderFrame* render_frame) {
......@@ -88,7 +95,8 @@ void SubresourceFilterAgent::OnActivateForNextCommittedLoad(
const ActivationState& activation_state,
bool is_ad_subframe) {
activation_state_for_next_commit_ = activation_state;
is_ad_subframe_for_next_commit_ = is_ad_subframe;
if (is_ad_subframe)
SetIsAdSubframe();
}
void SubresourceFilterAgent::RecordHistogramsOnLoadCommitted(
......@@ -152,7 +160,6 @@ void SubresourceFilterAgent::RecordHistogramsOnLoadFinished() {
void SubresourceFilterAgent::ResetInfoForNextCommit() {
activation_state_for_next_commit_ =
ActivationState(ActivationLevel::DISABLED);
is_ad_subframe_for_next_commit_ = false;
}
void SubresourceFilterAgent::OnDestruct() {
......@@ -176,7 +183,6 @@ void SubresourceFilterAgent::DidCommitProvisionalLoad(
const ActivationState activation_state =
use_parent_activation ? GetParentActivationState(render_frame())
: activation_state_for_next_commit_;
bool is_ad_subframe = is_ad_subframe_for_next_commit_;
ResetInfoForNextCommit();
......@@ -202,7 +208,7 @@ void SubresourceFilterAgent::DidCommitProvisionalLoad(
AsWeakPtr()));
auto filter = std::make_unique<WebDocumentSubresourceFilterImpl>(
url::Origin::Create(url), activation_state, std::move(ruleset),
std::move(first_disallowed_load_callback), is_ad_subframe);
std::move(first_disallowed_load_callback), IsAdSubframe());
filter_for_last_committed_load_ = filter->AsWeakPtr();
SetSubresourceFilterForCommittedLoad(std::move(filter));
......@@ -240,11 +246,6 @@ void SubresourceFilterAgent::WillCreateWorkerFetchContext(
if (!ruleset_file.IsValid())
return;
// Propagate the information to the worker whether this is associated with an
// ad subframe.
bool is_ad_subframe =
render_frame()->GetWebFrame()->GetDocumentLoader()->GetIsAdSubframe();
worker_fetch_context->SetSubresourceFilterBuilder(
std::make_unique<WebDocumentSubresourceFilterImpl::BuilderImpl>(
url::Origin::Create(GetDocumentURL()),
......@@ -253,7 +254,7 @@ void SubresourceFilterAgent::WillCreateWorkerFetchContext(
base::BindOnce(&SubresourceFilterAgent::
SignalFirstSubresourceDisallowedForCommittedLoad,
AsWeakPtr()),
is_ad_subframe));
IsAdSubframe()));
}
} // namespace subresource_filter
......@@ -60,6 +60,10 @@ class SubresourceFilterAgent
virtual void SendDocumentLoadStatistics(
const DocumentLoadStatistics& statistics);
// True if the frame has been heuristically determined to be an ad subframe.
virtual bool IsAdSubframe();
virtual void SetIsAdSubframe();
private:
// Assumes that the parent will be in a local frame relative to this one, upon
// construction.
......@@ -86,13 +90,6 @@ class SubresourceFilterAgent
ActivationState activation_state_for_next_commit_;
// This is received along with activation state in the
// SubresourceFilterMsg_ActivateForNextCommittedLoad IPC message. Specifies
// whether this is a subframe which is identified as an ad. Note that this
// will only be set in dry run mode because in blocking mode the frame would
// have been blocked.
bool is_ad_subframe_for_next_commit_;
base::WeakPtr<WebDocumentSubresourceFilterImpl>
filter_for_last_committed_load_;
......
......@@ -59,7 +59,10 @@ class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent {
OnSetSubresourceFilterForCommittedLoadCalled();
}
bool GetIsAssociatedWithAdSubframe() {
bool IsAdSubframe() override { return is_ad_subframe_; }
void SetIsAdSubframe() override { is_ad_subframe_ = true; }
bool IsFilterAssociatedWithAdSubframe() {
return last_injected_filter_->GetIsAssociatedWithAdSubframe();
}
......@@ -73,6 +76,7 @@ class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent {
private:
std::unique_ptr<blink::WebDocumentSubresourceFilter> last_injected_filter_;
bool is_ad_subframe_ = false;
DISALLOW_COPY_AND_ASSIGN(SubresourceFilterAgentUnderTest);
};
......@@ -467,6 +471,9 @@ TEST_F(SubresourceFilterAgentTest, DryRun_ResourcesAreEvaluatedButNotFiltered) {
// Performance measurement is switched off.
histogram_tester.ExpectTotalCount(kEvaluationTotalWallDuration, 0);
histogram_tester.ExpectTotalCount(kEvaluationTotalCPUDuration, 0);
EXPECT_FALSE(agent()->IsFilterAssociatedWithAdSubframe());
EXPECT_FALSE(agent()->IsAdSubframe());
}
TEST_F(SubresourceFilterAgentTest,
......@@ -532,7 +539,21 @@ TEST_F(SubresourceFilterAgentTest,
// For testing the flag passed to the dedicated worker filter, the unit test
// is not able to test the implementation of WillCreateWorkerFetchContext as
// that will require setup of a WebWorkerFetchContextImpl.
EXPECT_TRUE(agent()->GetIsAssociatedWithAdSubframe());
EXPECT_TRUE(agent()->IsFilterAssociatedWithAdSubframe());
EXPECT_TRUE(agent()->IsAdSubframe());
}
TEST_F(SubresourceFilterAgentTest, DryRun_FrameAlreadyTaggedAsAd) {
agent()->SetIsAdSubframe();
ASSERT_NO_FATAL_FAILURE(
SetTestRulesetToDisallowURLsWithPathSuffix("somethingNotMatched"));
ExpectSubresourceFilterGetsInjected();
StartLoadAndSetActivationState(ActivationState(ActivationLevel::DRYRUN),
false /* is_associated_with_ad_subframe */);
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
EXPECT_TRUE(agent()->IsFilterAssociatedWithAdSubframe());
EXPECT_TRUE(agent()->IsAdSubframe());
}
} // namespace subresource_filter
......@@ -146,8 +146,6 @@ class BLINK_EXPORT WebDocumentLoader {
// initiated loads that may have had a user activation from the browser UI.
virtual void SetUserActivated() = 0;
virtual bool GetIsAdSubframe() const = 0;
// Can be used to temporarily suspend feeding the parser with new data. The
// parser will be allowed to read new data when ResumeParser() is called the
// same number of time than BlockParser().
......
......@@ -872,6 +872,16 @@ class WebLocalFrame : public WebFrame {
virtual WebPerformance Performance() const = 0;
// Ad Tagging ---------------------------------------------------------
// True if the frame is thought (heuristically) to be created for
// advertising purposes.
virtual bool IsAdSubframe() const = 0;
// This setter is available in case the embedder has more information about
// whether or not the frame is an ad.
virtual void SetIsAdSubframe() = 0;
// Testing ------------------------------------------------------------------
// Dumps the layer tree, used by the accelerated compositor, in
......
......@@ -205,10 +205,6 @@ void WebDocumentLoaderImpl::SetUserActivated() {
DocumentLoader::SetUserActivated();
}
bool WebDocumentLoaderImpl::GetIsAdSubframe() const {
return GetSubresourceFilter()->GetIsAssociatedWithAdSubframe();
}
void WebDocumentLoaderImpl::BlockParser() {
DocumentLoader::BlockParser();
}
......
......@@ -85,7 +85,6 @@ class CORE_EXPORT WebDocumentLoaderImpl final : public DocumentLoader,
void SetSourceLocation(const WebSourceLocation&) override;
void ResetSourceLocation() override;
void SetUserActivated() override;
bool GetIsAdSubframe() const override;
void BlockParser() override;
void ResumeParser() override;
bool IsArchive() const override;
......
......@@ -93,11 +93,6 @@ void AdTracker::WillSendRequest(ExecutionContext* execution_context,
AppendToKnownAdScripts(request.Url());
}
// This is a separate function for testing purposes.
void AdTracker::AppendToKnownAdScripts(const KURL& url) {
known_ad_scripts_.insert(url.GetString());
}
bool AdTracker::AnyExecutingScriptsTaggedAsAdResource(
ExecutionContext* execution_context) {
// The pseudo-stack contains entry points into the stack (e.g., when v8 is
......@@ -115,6 +110,11 @@ bool AdTracker::AnyExecutingScriptsTaggedAsAdResource(
return false;
}
// This is a separate function for testing purposes.
void AdTracker::AppendToKnownAdScripts(const KURL& url) {
known_ad_scripts_.insert(url.GetString());
}
void AdTracker::Trace(blink::Visitor* visitor) {
visitor->Trace(local_root_);
}
......
......@@ -51,6 +51,10 @@ class CORE_EXPORT AdTracker : public GarbageCollectedFinalized<AdTracker> {
const FetchInitiatorInfo&,
Resource::Type);
// Returns true if any script in the pseudo call stack have previously been
// identified as an ad resource.
bool AnyExecutingScriptsTaggedAsAdResource(ExecutionContext*);
virtual void Trace(blink::Visitor*);
void Shutdown();
......@@ -69,11 +73,6 @@ class CORE_EXPORT AdTracker : public GarbageCollectedFinalized<AdTracker> {
void DidExecuteScript();
void AppendToKnownAdScripts(const KURL&);
// 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(ExecutionContext*);
Member<LocalFrame> local_root_;
// Since the script URLs should be external strings in v8 (allocated in Blink)
......
......@@ -894,6 +894,9 @@ inline LocalFrame::LocalFrame(LocalFrameClient* client,
}
idleness_detector_ = new IdlenessDetector(this);
inspector_task_runner_->InitIsolate(V8PerIsolateData::MainThreadIsolate());
if (ComputeIsAdSubFrame())
SetIsAdSubframe();
}
FrameScheduler* LocalFrame::GetFrameScheduler() {
......@@ -1142,6 +1145,20 @@ bool LocalFrame::CanNavigateWithoutFramebusting(const Frame& target_frame,
return false;
}
bool LocalFrame::ComputeIsAdSubFrame() const {
DCHECK(ad_tracker_);
Frame* parent = Tree().Parent();
if (!parent)
return false;
// If the parent frame is local, directly determine if it's an ad. If
// it's remote, then blink relies on the embedder to call SetIsAdFrame.
bool parent_is_ad =
parent->IsLocalFrame() && ToLocalFrame(parent)->IsAdSubframe();
return parent_is_ad ||
ad_tracker_->AnyExecutingScriptsTaggedAsAdResource(GetDocument());
}
service_manager::InterfaceProvider& LocalFrame::GetInterfaceProvider() {
DCHECK(Client());
return *Client()->GetInterfaceProvider();
......
......@@ -327,6 +327,13 @@ class CORE_EXPORT LocalFrame final : public Frame,
ComputedAccessibleNode* GetOrCreateComputedAccessibleNode(AXID,
WebComputedAXTree*);
// True if AdTracker heuristics have determined that this frame is an ad.
bool IsAdSubframe() const { return is_ad_subframe_; }
void SetIsAdSubframe() {
DCHECK(!IsMainFrame());
is_ad_subframe_ = true;
}
private:
friend class FrameNavigationDisabler;
......@@ -345,6 +352,8 @@ class CORE_EXPORT LocalFrame final : public Frame,
bool CanNavigateWithoutFramebusting(const Frame&, String& error_reason);
bool ComputeIsAdSubFrame() const;
void PropagateInertToChildFrames();
// Internal implementation for starting or ending printing.
......@@ -390,6 +399,12 @@ class CORE_EXPORT LocalFrame final : public Frame,
bool in_view_source_mode_;
// True if this frame is heuristically determined to have been created for
// advertising purposes. It's per-frame (as opposed to per-document) because
// when an iframe is created on behalf of ad script that same frame is not
// typically reused for non-ad purposes.
bool is_ad_subframe_ = false;
Member<CoreProbeSink> probe_sink_;
scoped_refptr<InspectorTaskRunner> inspector_task_runner_;
Member<PerformanceMonitor> performance_monitor_;
......
......@@ -659,6 +659,16 @@ WebPerformance WebLocalFrameImpl::Performance() const {
DOMWindowPerformance::performance(*(GetFrame()->DomWindow())));
}
bool WebLocalFrameImpl::IsAdSubframe() const {
DCHECK(GetFrame());
return GetFrame()->IsAdSubframe();
}
void WebLocalFrameImpl::SetIsAdSubframe() {
DCHECK(GetFrame());
GetFrame()->SetIsAdSubframe();
}
void WebLocalFrameImpl::DispatchUnloadEvent() {
if (!GetFrame())
return;
......
......@@ -98,6 +98,8 @@ class CORE_EXPORT WebLocalFrameImpl final
WebView* View() const override;
WebDocument GetDocument() const override;
WebPerformance Performance() const override;
bool IsAdSubframe() const override;
void SetIsAdSubframe() override;
void DispatchUnloadEvent() override;
void ExecuteScript(const WebScriptSource&) override;
void ExecuteScriptInIsolatedWorld(int world_id,
......
......@@ -91,10 +91,6 @@ bool SubresourceFilter::AllowWebSocketConnection(const KURL& url) {
return load_policy != WebDocumentSubresourceFilter::kDisallow;
}
bool SubresourceFilter::GetIsAssociatedWithAdSubframe() {
return subresource_filter_->GetIsAssociatedWithAdSubframe();
}
bool SubresourceFilter::IsAdResource(
const KURL& resource_url,
WebURLRequest::RequestContext request_context) {
......
......@@ -36,8 +36,6 @@ class CORE_EXPORT SubresourceFilter final
SecurityViolationReportingPolicy);
bool AllowWebSocketConnection(const KURL&);
bool GetIsAssociatedWithAdSubframe();
// Returns if |resource_url| is an ad resource.
bool IsAdResource(const KURL& resource_url, WebURLRequest::RequestContext);
......
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