blob: f01e07d20683cb891ce44176f7a104e3cb93c060 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_AD_TRACKER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_AD_TRACKER_H_
#include <stdint.h>
#include <optional>
#include "base/feature_list.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/frame/ad_script_identifier.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_info.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "v8/include/v8.h"
namespace blink {
class Document;
class ExecutionContext;
class LocalFrame;
enum class ResourceType : uint8_t;
namespace probe {
class AsyncTaskContext;
class CallFunction;
class ExecuteScript;
} // namespace probe
namespace features {
CORE_EXPORT BASE_DECLARE_FEATURE(kAsyncStackAdTagging);
} // namespace features
// Tracker for tagging resources as ads based on the call stack scripts.
// The tracker is maintained per local root.
class CORE_EXPORT AdTracker : public GarbageCollected<AdTracker> {
public:
enum class StackType { kBottomOnly, kBottomAndTop };
// Finds an AdTracker for a given ExecutionContext.
static AdTracker* FromExecutionContext(ExecutionContext*);
static bool IsAdScriptExecutingInDocument(
Document* document,
StackType stack_type = StackType::kBottomAndTop);
// Instrumenting methods.
// Called when a script module or script gets executed from native code.
void Will(const probe::ExecuteScript&);
void Did(const probe::ExecuteScript&);
// Called when a function gets called from native code.
void Will(const probe::CallFunction&);
void Did(const probe::CallFunction&);
// Called when a subresource request is about to be sent or is redirected.
// Returns true if any of the following are true:
// - the resource is loaded in an ad iframe
// - |known_ad| is true
// - ad script is in the v8 stack and the resource was not requested by CSS.
// Virtual for testing.
virtual bool CalculateIfAdSubresource(
ExecutionContext* execution_context,
const KURL& request_url,
ResourceType resource_type,
const FetchInitiatorInfo& initiator_info,
bool known_ad);
// Called when an async task is created. Check at this point for ad script on
// the stack and annotate the task if so.
void DidCreateAsyncTask(probe::AsyncTaskContext* task_context);
// Called when an async task is eventually run.
void DidStartAsyncTask(probe::AsyncTaskContext* task_context);
// Called when the task has finished running.
void DidFinishAsyncTask(probe::AsyncTaskContext* task_context);
// Returns true if any script in the pseudo call stack has previously been
// identified as an ad resource, if the current ExecutionContext is a known ad
// execution context, or if the script at the top of isolate's
// stack is ad script. Whether to look at just the bottom of the
// stack or the top and bottom is indicated by `stack_type`. kBottomAndTop is
// generally best as it catches more ads, but if you're calling very
// frequently then consider just the bottom of the stack for performance sake.
// If `out_ad_script` is non-null and there is ad script in the stack, the
// bottom-most known ad script on the stack will be copied to the address.
bool IsAdScriptInStack(
StackType stack_type,
std::optional<AdScriptIdentifier>* out_ad_script = nullptr);
virtual void Trace(Visitor*) const;
void Shutdown();
explicit AdTracker(LocalFrame*);
AdTracker(const AdTracker&) = delete;
AdTracker& operator=(const AdTracker&) = delete;
virtual ~AdTracker();
protected:
// Protected for testing.
virtual String ScriptAtTopOfStack();
virtual ExecutionContext* GetCurrentExecutionContext();
private:
friend class FrameFetchContextSubresourceFilterTest;
friend class AdTrackerSimTest;
friend class AdTrackerTest;
// |script_name| will be empty in the case of a dynamically added script with
// no src attribute set. |script_id| won't be set for module scripts in an
// errored state or for non-source text modules.
void WillExecuteScript(ExecutionContext*,
const v8::Local<v8::Context>& v8_context,
const String& script_name,
int script_id);
void DidExecuteScript();
bool IsKnownAdScript(ExecutionContext*, const String& url);
bool IsKnownAdScriptForCheckedContext(ExecutionContext&, const String& url);
void AppendToKnownAdScripts(ExecutionContext&, const String& url);
Member<LocalFrame> local_root_;
// Each time v8 is started to run a script or function, this records if it was
// an ad script. Each time the script or function finishes, it pops the stack.
Vector<bool> stack_frame_is_ad_;
int num_ads_in_stack_ = 0;
// Indicates the bottom-most ad script on the stack or `std::nullopt` if
// there isn't one. A non-null value implies `num_ads_in_stack > 0`.
std::optional<AdScriptIdentifier> bottom_most_ad_script_;
// Indicates the bottom-most ad script on the async stack or `std::nullopt`
// if there isn't one.
std::optional<AdScriptIdentifier> bottom_most_async_ad_script_;
// The set of ad scripts detected outside of ad-frame contexts. Scripts are
// identified by name (i.e. resource URL). Scripts with no name (i.e. inline
// scripts) use a String created by GenerateFakeUrlFromScriptId() instead.
HeapHashMap<WeakMember<ExecutionContext>, HashSet<String>> known_ad_scripts_;
// The number of ad-related async tasks currently running in the stack.
int running_ad_async_tasks_ = 0;
// True if the AdTracker looks not only at the current V8 stack for ad script
// but also at the previous asynchronous stacks that caused this current
// callstack to run (e.g., registered callbacks).
const bool async_stack_enabled_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_AD_TRACKER_H_