Commit 73d8aa4d authored by Charlie Hu's avatar Charlie Hu Committed by Commit Bot

[Document Policy] Deduplicate document policy violation report

Most image policies can report multiple violations for a single cause(same image not following the rule) during layout, e.g. An unoptimized-lossless-image's bpp(byte per pixel) value can change multiple times if the image is being scaled in an animation.

To avoid unnecessary duplicated reports being generated. This CL adds Hash method for DocumentPolicyViolationReport to uniquely identify each report and avoid the duplication by remembering these hash values in LocalDOMWindow and filter out reports that are in record.

Bug: 924684, 926199
Change-Id: I785ad8b36ef372188da1b2cc4e25886e59c1e18b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2405646
Commit-Queue: Charlie Hu <chenleihu@google.com>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarJason Chase <chasej@chromium.org>
Cr-Commit-Position: refs/heads/master@{#813231}
parent 809126fe
...@@ -1133,6 +1133,7 @@ source_set("unit_tests") { ...@@ -1133,6 +1133,7 @@ source_set("unit_tests") {
"frame/csp/string_list_directive_test.cc", "frame/csp/string_list_directive_test.cc",
"frame/deprecation_report_body_test.cc", "frame/deprecation_report_body_test.cc",
"frame/document_loading_rendering_test.cc", "frame/document_loading_rendering_test.cc",
"frame/document_policy_violation_report_body_test.cc",
"frame/dom_timer_test.cc", "frame/dom_timer_test.cc",
"frame/find_in_page_test.cc", "frame/find_in_page_test.cc",
"frame/frame_overlay_test.cc", "frame/frame_overlay_test.cc",
...@@ -1144,9 +1145,11 @@ source_set("unit_tests") { ...@@ -1144,9 +1145,11 @@ source_set("unit_tests") {
"frame/local_frame_test.cc", "frame/local_frame_test.cc",
"frame/local_frame_ukm_aggregator_test.cc", "frame/local_frame_ukm_aggregator_test.cc",
"frame/local_frame_view_test.cc", "frame/local_frame_view_test.cc",
"frame/location_report_body_test.cc",
"frame/mhtml_archive_test.cc", "frame/mhtml_archive_test.cc",
"frame/mhtml_loading_test.cc", "frame/mhtml_loading_test.cc",
"frame/performance_monitor_test.cc", "frame/performance_monitor_test.cc",
"frame/report_test.cc",
"frame/reporting_context_test.cc", "frame/reporting_context_test.cc",
"frame/root_frame_viewport_test.cc", "frame/root_frame_viewport_test.cc",
"frame/rotation_viewport_anchor_test.cc", "frame/rotation_viewport_anchor_test.cc",
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#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/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/reporting_context.h"
#include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/viewport_data.h" #include "third_party/blink/renderer/core/frame/viewport_data.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h" #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
...@@ -72,6 +73,8 @@ ...@@ -72,6 +73,8 @@
#include "third_party/blink/renderer/core/testing/color_scheme_helper.h" #include "third_party/blink/renderer/core/testing/color_scheme_helper.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h" #include "third_party/blink/renderer/core/testing/scoped_mock_overlay_scrollbars.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
...@@ -107,6 +110,8 @@ void DocumentTest::SetHtmlInnerHTML(const char* html_content) { ...@@ -107,6 +110,8 @@ void DocumentTest::SetHtmlInnerHTML(const char* html_content) {
UpdateAllLifecyclePhasesForTest(); UpdateAllLifecyclePhasesForTest();
} }
class DocumentSimTest : public SimTest {};
namespace { namespace {
class TestSynchronousMutationObserver class TestSynchronousMutationObserver
...@@ -1356,4 +1361,46 @@ TEST_F(DocumentBatterySavingsTest, ChromeClientCalls) { ...@@ -1356,4 +1361,46 @@ TEST_F(DocumentBatterySavingsTest, ChromeClientCalls) {
second->setAttribute(html_names::kNameAttr, "viewport"); second->setAttribute(html_names::kNameAttr, "viewport");
} }
namespace {
class MockReportingContext final : public ReportingContext {
public:
explicit MockReportingContext(ExecutionContext& ec) : ReportingContext(ec) {}
void QueueReport(Report* report, const Vector<String>& endpoint) override {
report_count++;
}
unsigned report_count = 0;
};
} // namespace
TEST_F(DocumentSimTest, DuplicatedDocumentPolicyViolationsAreIgnored) {
blink::ScopedDocumentPolicyForTest scoped_document_policy(true);
SimRequest::Params params;
params.response_http_headers = {
{"Document-Policy", "lossless-images-max-bpp=1.0"}};
SimRequest main_resource("https://example.com", "text/html", params);
LoadURL("https://example.com");
main_resource.Finish();
ExecutionContext* execution_context = GetDocument().GetExecutionContext();
MockReportingContext* mock_reporting_context =
MakeGarbageCollected<MockReportingContext>(*execution_context);
Supplement<ExecutionContext>::ProvideTo(*execution_context,
mock_reporting_context);
EXPECT_FALSE(execution_context->IsFeatureEnabled(
mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
PolicyValue::CreateDecDouble(1.1), ReportOptions::kReportOnFailure));
EXPECT_EQ(mock_reporting_context->report_count, 1u);
EXPECT_FALSE(execution_context->IsFeatureEnabled(
mojom::blink::DocumentPolicyFeature::kLosslessImagesMaxBpp,
PolicyValue::CreateDecDouble(1.1), ReportOptions::kReportOnFailure));
EXPECT_EQ(mock_reporting_context->report_count, 1u);
}
} // namespace blink } // namespace blink
...@@ -3,9 +3,27 @@ ...@@ -3,9 +3,27 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "third_party/blink/renderer/core/frame/document_policy_violation_report_body.h" #include "third_party/blink/renderer/core/frame/document_policy_violation_report_body.h"
#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
namespace blink { namespace blink {
DocumentPolicyViolationReportBody::DocumentPolicyViolationReportBody(
const String& feature_id,
const String& message,
const String& disposition,
// URL of the resource that violated the document policy.
const String& resource_url)
: LocationReportBody(resource_url),
feature_id_(feature_id),
message_("Document policy violation: " +
(message.IsEmpty()
? feature_id + " is not allowed in this document."
: message)),
disposition_(disposition) {
DCHECK(!feature_id.IsEmpty());
DCHECK(!disposition.IsEmpty());
}
void DocumentPolicyViolationReportBody::BuildJSONValue( void DocumentPolicyViolationReportBody::BuildJSONValue(
V8ObjectBuilder& builder) const { V8ObjectBuilder& builder) const {
LocationReportBody::BuildJSONValue(builder); LocationReportBody::BuildJSONValue(builder);
...@@ -14,4 +32,12 @@ void DocumentPolicyViolationReportBody::BuildJSONValue( ...@@ -14,4 +32,12 @@ void DocumentPolicyViolationReportBody::BuildJSONValue(
builder.AddStringOrNull("message", message()); builder.AddStringOrNull("message", message());
} }
unsigned DocumentPolicyViolationReportBody::MatchId() const {
unsigned hash = LocationReportBody::MatchId();
hash = WTF::HashInts(hash, featureId().Impl()->GetHash());
hash = WTF::HashInts(hash, disposition().Impl()->GetHash());
hash = WTF::HashInts(hash, message().Impl()->GetHash());
return hash;
}
} // namespace blink } // namespace blink
...@@ -21,14 +21,7 @@ class CORE_EXPORT DocumentPolicyViolationReportBody ...@@ -21,14 +21,7 @@ class CORE_EXPORT DocumentPolicyViolationReportBody
const String& message, const String& message,
const String& disposition, const String& disposition,
// URL of the resource that violated the document policy. // URL of the resource that violated the document policy.
const String& resource_url) const String& resource_url);
: LocationReportBody(resource_url),
feature_id_(feature_id),
message_("Document policy violation: " +
(message.IsEmpty()
? feature_id + " is not allowed in this document."
: message)),
disposition_(disposition) {}
const String& featureId() const { return feature_id_; } const String& featureId() const { return feature_id_; }
const String& disposition() const { return disposition_; } const String& disposition() const { return disposition_; }
...@@ -38,6 +31,8 @@ class CORE_EXPORT DocumentPolicyViolationReportBody ...@@ -38,6 +31,8 @@ class CORE_EXPORT DocumentPolicyViolationReportBody
~DocumentPolicyViolationReportBody() override = default; ~DocumentPolicyViolationReportBody() override = default;
unsigned MatchId() const override;
private: private:
const String feature_id_; const String feature_id_;
const String message_; const String message_;
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/frame/document_policy_violation_report_body.h"
#include <set>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
namespace {
// Test whether DocumentPolicyViolationReportBody::MatchId() is a pure function,
// i.e. same input will give same return value. The input values are randomly
// picked values.
TEST(DocumentPolicyViolationReportBodyMatchIdTest,
SameInputGeneratesSameMatchId) {
String feature_id = "feature_id";
String message = "";
String disposition = "enforce";
String resource_url = "";
EXPECT_EQ(DocumentPolicyViolationReportBody(feature_id, message, disposition,
resource_url)
.MatchId(),
DocumentPolicyViolationReportBody(feature_id, message, disposition,
resource_url)
.MatchId());
feature_id = "unoptimized_images";
message = "document policy violation";
disposition = "report";
resource_url = "resource url";
EXPECT_EQ(DocumentPolicyViolationReportBody(feature_id, message, disposition,
resource_url)
.MatchId(),
DocumentPolicyViolationReportBody(feature_id, message, disposition,
resource_url)
.MatchId());
}
bool AllDistinct(const std::vector<unsigned>& match_ids) {
return match_ids.size() ==
std::set<unsigned>(match_ids.begin(), match_ids.end()).size();
}
const struct {
const char* feature_id;
const char* message;
const char* disposition;
const char* resource_url;
} kDocumentPolicyViolationReportBodyInputs[] = {
{"a", "", "c", "d"},
{"a", "b", "c", ""},
{"a", "b", "c", "d"},
{"a", "b", "c", "e"},
};
TEST(DocumentPolicyViolationReportBodyMatchIdTest,
DifferentInputsGenerateDifferentMatchId) {
std::vector<unsigned> match_ids;
for (const auto& input : kDocumentPolicyViolationReportBodyInputs) {
match_ids.push_back(
DocumentPolicyViolationReportBody(input.feature_id, input.message,
input.disposition, input.resource_url)
.MatchId());
}
EXPECT_TRUE(AllDistinct(match_ids));
}
TEST(DocumentPolicyViolationReportBodyMatchIdTest,
MatchIdGeneratedShouldNotBeZero) {
std::vector<unsigned> match_ids;
for (const auto& input : kDocumentPolicyViolationReportBodyInputs) {
EXPECT_NE(
DocumentPolicyViolationReportBody(input.feature_id, input.message,
input.disposition, input.resource_url)
.MatchId(),
0u);
}
}
// In |DocumentPolicyViolationReportBody|, empty message string and null message
// string are both treated as empty string and a default message will be
// generated.
TEST(DocumentPolicyViolationReportBodyMatchIdTest,
EmptyMessageGenerateSameResult) {
EXPECT_EQ(
DocumentPolicyViolationReportBody("feature_id", "message", "disposition",
g_empty_string)
.MatchId(),
DocumentPolicyViolationReportBody("feature_id", "message", "disposition",
String() /* null string */)
.MatchId());
}
} // namespace
} // namespace blink
...@@ -490,6 +490,20 @@ void LocalDOMWindow::ReportDocumentPolicyViolation( ...@@ -490,6 +490,20 @@ void LocalDOMWindow::ReportDocumentPolicyViolation(
Report* report = MakeGarbageCollected<Report>( Report* report = MakeGarbageCollected<Report>(
ReportType::kDocumentPolicyViolation, Url().GetString(), body); ReportType::kDocumentPolicyViolation, Url().GetString(), body);
// Avoids sending duplicate reports, by comparing the generated MatchId.
// The match ids are not guaranteed to be unique.
// There are trade offs on storing full objects and storing match ids. Storing
// full objects takes more memory. Storing match id has the potential of hash
// collision. Since reporting is not a part critical system or have security
// concern, dropping a valid report due to hash collision seems a reasonable
// price to pay for the memory saving.
unsigned report_id = report->MatchId();
DCHECK(report_id);
if (document_policy_violation_reports_sent_.Contains(report_id))
return;
document_policy_violation_reports_sent_.insert(report_id);
// Send the document policy violation report to any ReportingObservers. // Send the document policy violation report to any ReportingObservers.
const base::Optional<std::string> endpoint = const base::Optional<std::string> endpoint =
relevant_document_policy->GetFeatureEndpoint(feature); relevant_document_policy->GetFeatureEndpoint(feature);
......
...@@ -512,6 +512,11 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow, ...@@ -512,6 +512,11 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
// creation. Remains valid even after the frame is destroyed and the context // creation. Remains valid even after the frame is destroyed and the context
// is detached. // is detached.
const LocalFrameToken token_; const LocalFrameToken token_;
// Tracks which document policy violation reports have already been sent in
// this document, to avoid reporting duplicates. The value stored comes
// from |DocumentPolicyViolationReport::MatchId()|.
mutable HashSet<unsigned> document_policy_violation_reports_sent_;
}; };
template <> template <>
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "third_party/blink/renderer/core/frame/location_report_body.h" #include "third_party/blink/renderer/core/frame/location_report_body.h"
#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
namespace blink { namespace blink {
...@@ -38,4 +39,15 @@ void LocationReportBody::BuildJSONValue(V8ObjectBuilder& builder) const { ...@@ -38,4 +39,15 @@ void LocationReportBody::BuildJSONValue(V8ObjectBuilder& builder) const {
} }
} }
unsigned LocationReportBody::MatchId() const {
const base::Optional<uint32_t> line = lineNumber(), column = columnNumber();
unsigned hash = sourceFile().IsNull() ? 0 : sourceFile().Impl()->GetHash();
hash = WTF::HashInts(hash,
line ? DefaultHash<uint32_t>::Hash::GetHash(*line) : 0);
hash = WTF::HashInts(
hash, column ? DefaultHash<uint32_t>::Hash::GetHash(*column) : 0);
return hash;
}
} // namespace blink } // namespace blink
...@@ -56,6 +56,8 @@ class CORE_EXPORT LocationReportBody : public ReportBody { ...@@ -56,6 +56,8 @@ class CORE_EXPORT LocationReportBody : public ReportBody {
void BuildJSONValue(V8ObjectBuilder& builder) const override; void BuildJSONValue(V8ObjectBuilder& builder) const override;
unsigned MatchId() const override;
protected: protected:
const String source_file_; const String source_file_;
const base::Optional<uint32_t> line_number_; const base::Optional<uint32_t> line_number_;
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/frame/location_report_body.h"
#include <set>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
namespace {
class TestLocationReportBody : public LocationReportBody {
public:
explicit TestLocationReportBody(
const String& source_file = g_empty_string,
base::Optional<uint32_t> line_number = base::nullopt,
base::Optional<uint32_t> column_number = base::nullopt)
: LocationReportBody(source_file, line_number, column_number) {}
};
// Test whether LocationReportBody::MatchId() is a pure function, i.e. same
// input will give same return value.
TEST(LocationReportBodyMatchIdTest, SameInputGeneratesSameMatchId) {
String url = "";
base::Optional<uint32_t> line = base::nullopt, column = base::nullopt;
EXPECT_EQ(TestLocationReportBody(url, line, column).MatchId(),
TestLocationReportBody(url, line, column).MatchId());
url = "https://example.com";
line = base::make_optional<uint32_t>(0);
column = base::make_optional<uint32_t>(0);
EXPECT_EQ(TestLocationReportBody(url, line, column).MatchId(),
TestLocationReportBody(url, line, column).MatchId());
}
bool AllDistinct(const std::vector<unsigned>& match_ids) {
return match_ids.size() ==
std::set<unsigned>(match_ids.begin(), match_ids.end()).size();
}
const struct {
const char* url;
const base::Optional<uint32_t> line_number;
const base::Optional<uint32_t> column_number;
} kLocationReportBodyInputs[] = {
{"url", base::nullopt, base::nullopt},
{"url", 0, base::nullopt},
{"url", base::nullopt, 0},
{"url", 0, 0},
{"url", 1, base::nullopt},
{"url", base::nullopt, 1},
{"url", 1, 1},
};
TEST(LocationReportBodyMatchIdTest, DifferentInputsGenerateDifferentMatchId) {
std::vector<unsigned> match_ids;
for (const auto& input : kLocationReportBodyInputs) {
match_ids.push_back(TestLocationReportBody(input.url, input.line_number,
input.column_number)
.MatchId());
}
EXPECT_TRUE(AllDistinct(match_ids));
}
TEST(LocationReportBodyMatchIdTest, MatchIdGeneratedShouldNotBeZero) {
std::vector<unsigned> match_ids;
for (const auto& input : kLocationReportBodyInputs) {
EXPECT_NE(TestLocationReportBody(input.url, input.line_number,
input.column_number)
.MatchId(),
0u);
}
}
// When URL is empty, LocationReportBody would call |SourceLocation::Capture()|
// to determine the location, and ignore |line_number| and |column_number|
// specified in constructor params.
TEST(LocationReportBodyMatchIdTest,
EmptyURLGenerateSameMatchIdRegardlessOfOtherParams) {
const unsigned empty_hash =
TestLocationReportBody("", base::nullopt, base::nullopt).MatchId();
for (const auto& input : kLocationReportBodyInputs) {
EXPECT_EQ(TestLocationReportBody("", input.line_number, input.column_number)
.MatchId(),
empty_hash);
}
}
} // namespace
} // namespace blink
...@@ -23,4 +23,11 @@ ScriptValue Report::toJSON(ScriptState* script_state) const { ...@@ -23,4 +23,11 @@ ScriptValue Report::toJSON(ScriptState* script_state) const {
return builder.GetScriptValue(); return builder.GetScriptValue();
} }
unsigned Report::MatchId() const {
unsigned hash = body()->MatchId();
hash = WTF::HashInts(hash, url().IsNull() ? 0 : url().Impl()->GetHash());
hash = WTF::HashInts(hash, type().Impl()->GetHash());
return hash;
}
} // namespace blink } // namespace blink
...@@ -29,7 +29,9 @@ class CORE_EXPORT Report : public ScriptWrappable { ...@@ -29,7 +29,9 @@ class CORE_EXPORT Report : public ScriptWrappable {
public: public:
Report(const String& type, const String& url, ReportBody* body) Report(const String& type, const String& url, ReportBody* body)
: type_(type), url_(url), body_(body) {} : type_(type), url_(url), body_(body) {
DCHECK(!type.IsNull());
}
~Report() override = default; ~Report() override = default;
...@@ -44,6 +46,10 @@ class CORE_EXPORT Report : public ScriptWrappable { ...@@ -44,6 +46,10 @@ class CORE_EXPORT Report : public ScriptWrappable {
ScriptValue toJSON(ScriptState* script_state) const; ScriptValue toJSON(ScriptState* script_state) const;
// Provides a hash-like value for identifying reports with same content.
// Collision of match id is possible.
unsigned MatchId() const;
private: private:
const String type_; const String type_;
const String url_; const String url_;
......
...@@ -20,6 +20,10 @@ class CORE_EXPORT ReportBody : public ScriptWrappable { ...@@ -20,6 +20,10 @@ class CORE_EXPORT ReportBody : public ScriptWrappable {
// This function is public for use in Report::toJSON // This function is public for use in Report::toJSON
virtual void BuildJSONValue(V8ObjectBuilder& builder) const = 0; virtual void BuildJSONValue(V8ObjectBuilder& builder) const = 0;
// Provides a hash-like value for identifying reports with same content.
// Collision of match id is possible.
virtual unsigned MatchId() const { return 0; }
}; };
} // namespace blink } // namespace blink
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/frame/report.h"
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/frame/document_policy_violation_report_body.h"
#include "third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h"
#include "third_party/blink/renderer/core/frame/location_report_body.h"
namespace blink {
namespace {
// Test whether Report::MatchId() is a pure function, i.e. same input
// will give same return value.
// The input values are randomly picked values.
TEST(ReportMatchIdTest, SameInputGeneratesSameMatchId) {
String type = ReportType::kDocumentPolicyViolation;
String url = "";
String feature_id = "feature_id";
String message = "";
String disposition = "report";
String resource_url = "";
ReportBody* body = MakeGarbageCollected<DocumentPolicyViolationReportBody>(
feature_id, message, disposition, resource_url);
EXPECT_EQ(Report(type, url, body).MatchId(),
Report(type, url, body).MatchId());
type = ReportType::kDocumentPolicyViolation;
url = "https://example.com";
feature_id = "font-display-late-swap";
message = "document policy violation";
disposition = "enforce";
resource_url = "https://example.com/resource.png";
body = MakeGarbageCollected<DocumentPolicyViolationReportBody>(
feature_id, message, disposition, resource_url);
EXPECT_EQ(Report(type, url, body).MatchId(),
Report(type, url, body).MatchId());
}
bool AllDistinct(const std::vector<unsigned>& match_ids) {
return match_ids.size() ==
std::set<unsigned>(match_ids.begin(), match_ids.end()).size();
}
const struct {
const char* feature_id;
const char* message;
const char* disposition;
const char* resource_url;
const char* url;
} kReportInputs[] = {
{"a", "b", "c", "d", ""},
{"a", "b", "c", "d", "url"},
};
TEST(ReportMatchIdTest, DifferentInputsGenerateDifferentMatchId) {
std::vector<unsigned> match_ids;
for (const auto& input : kReportInputs) {
match_ids.push_back(
Report(ReportType::kDocumentPolicyViolation, input.url,
MakeGarbageCollected<DocumentPolicyViolationReportBody>(
input.feature_id, input.message, input.disposition,
input.resource_url))
.MatchId());
match_ids.push_back(
Report(ReportType::kFeaturePolicyViolation, input.url,
MakeGarbageCollected<FeaturePolicyViolationReportBody>(
input.feature_id, input.message, input.disposition))
.MatchId());
}
EXPECT_TRUE(AllDistinct(match_ids));
}
TEST(ReportMatchIdTest, MatchIdGeneratedShouldNotBeZero) {
std::vector<unsigned> match_ids;
for (const auto& input : kReportInputs) {
EXPECT_NE(Report(ReportType::kDocumentPolicyViolation, input.url,
MakeGarbageCollected<DocumentPolicyViolationReportBody>(
input.feature_id, input.message, input.disposition,
input.resource_url))
.MatchId(),
0u);
}
}
} // namespace
} // namespace blink
...@@ -22,10 +22,9 @@ class ReportingObserver; ...@@ -22,10 +22,9 @@ class ReportingObserver;
// ReportingContext processes all reports for an ExecutionContext, and serves as // ReportingContext processes all reports for an ExecutionContext, and serves as
// a container for all active ReportingObservers on that ExecutionContext. // a container for all active ReportingObservers on that ExecutionContext.
class CORE_EXPORT ReportingContext final class CORE_EXPORT ReportingContext : public GarbageCollected<ReportingContext>,
: public GarbageCollected<ReportingContext>, public mojom::blink::ReportingObserver,
public mojom::blink::ReportingObserver, public Supplement<ExecutionContext> {
public Supplement<ExecutionContext> {
public: public:
static const char kSupplementName[]; static const char kSupplementName[];
...@@ -40,7 +39,8 @@ class CORE_EXPORT ReportingContext final ...@@ -40,7 +39,8 @@ class CORE_EXPORT ReportingContext final
void Bind(mojo::PendingReceiver<mojom::blink::ReportingObserver> receiver); void Bind(mojo::PendingReceiver<mojom::blink::ReportingObserver> receiver);
// Queues a report for the Reporting API and in all registered observers. // Queues a report for the Reporting API and in all registered observers.
void QueueReport(Report*, const Vector<String>& endpoints = {"default"}); virtual void QueueReport(Report*,
const Vector<String>& endpoints = {"default"});
void RegisterObserver(blink::ReportingObserver*); void RegisterObserver(blink::ReportingObserver*);
void UnregisterObserver(blink::ReportingObserver*); void UnregisterObserver(blink::ReportingObserver*);
......
...@@ -538,7 +538,8 @@ TEST_F(DocumentLoaderSimTest, DocumentPolicyEnforcedReportHistogramTest) { ...@@ -538,7 +538,8 @@ TEST_F(DocumentLoaderSimTest, DocumentPolicyEnforcedReportHistogramTest) {
Window().ReportDocumentPolicyViolation( Window().ReportDocumentPolicyViolation(
mojom::blink::DocumentPolicyFeature::kFontDisplay, mojom::blink::DocumentPolicyFeature::kFontDisplay,
mojom::blink::PolicyDisposition::kEnforce); mojom::blink::PolicyDisposition::kEnforce,
"first font display violation");
histogram_tester.ExpectTotalCount("Blink.UseCounter.DocumentPolicy.Enforced", histogram_tester.ExpectTotalCount("Blink.UseCounter.DocumentPolicy.Enforced",
1); 1);
...@@ -548,7 +549,8 @@ TEST_F(DocumentLoaderSimTest, DocumentPolicyEnforcedReportHistogramTest) { ...@@ -548,7 +549,8 @@ TEST_F(DocumentLoaderSimTest, DocumentPolicyEnforcedReportHistogramTest) {
// Multiple reports should be recorded multiple times. // Multiple reports should be recorded multiple times.
Window().ReportDocumentPolicyViolation( Window().ReportDocumentPolicyViolation(
mojom::blink::DocumentPolicyFeature::kFontDisplay, mojom::blink::DocumentPolicyFeature::kFontDisplay,
mojom::blink::PolicyDisposition::kEnforce); mojom::blink::PolicyDisposition::kEnforce,
"second font display violation");
histogram_tester.ExpectTotalCount("Blink.UseCounter.DocumentPolicy.Enforced", histogram_tester.ExpectTotalCount("Blink.UseCounter.DocumentPolicy.Enforced",
2); 2);
...@@ -570,7 +572,7 @@ TEST_F(DocumentLoaderSimTest, DocumentPolicyReportOnlyReportHistogramTest) { ...@@ -570,7 +572,7 @@ TEST_F(DocumentLoaderSimTest, DocumentPolicyReportOnlyReportHistogramTest) {
Window().ReportDocumentPolicyViolation( Window().ReportDocumentPolicyViolation(
mojom::blink::DocumentPolicyFeature::kFontDisplay, mojom::blink::DocumentPolicyFeature::kFontDisplay,
mojom::blink::PolicyDisposition::kReport); mojom::blink::PolicyDisposition::kReport, "first font display violation");
histogram_tester.ExpectTotalCount( histogram_tester.ExpectTotalCount(
"Blink.UseCounter.DocumentPolicy.ReportOnly", 1); "Blink.UseCounter.DocumentPolicy.ReportOnly", 1);
...@@ -580,7 +582,8 @@ TEST_F(DocumentLoaderSimTest, DocumentPolicyReportOnlyReportHistogramTest) { ...@@ -580,7 +582,8 @@ TEST_F(DocumentLoaderSimTest, DocumentPolicyReportOnlyReportHistogramTest) {
// Multiple reports should be recorded multiple times. // Multiple reports should be recorded multiple times.
Window().ReportDocumentPolicyViolation( Window().ReportDocumentPolicyViolation(
mojom::blink::DocumentPolicyFeature::kFontDisplay, mojom::blink::DocumentPolicyFeature::kFontDisplay,
mojom::blink::PolicyDisposition::kReport); mojom::blink::PolicyDisposition::kReport,
"second font display violation");
histogram_tester.ExpectTotalCount( histogram_tester.ExpectTotalCount(
"Blink.UseCounter.DocumentPolicy.ReportOnly", 2); "Blink.UseCounter.DocumentPolicy.ReportOnly", 2);
......
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