Commit 67bbed9c authored by Paul Meyer's avatar Paul Meyer Committed by Commit Bot

Implement ReportingObserverOptions and the |buffered| option.

As per this spec:
https://wicg.github.io/reporting/#dictdef-reportingobserveroptions

Bug: 731810
Change-Id: I50840a97c2858fd04f397fd9799156d8e1e873c5
Reviewed-on: https://chromium-review.googlesource.com/1101312
Commit-Queue: Paul Meyer <paulmeyer@chromium.org>
Reviewed-by: default avatarNate Chapin <japhet@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568274}
parent 64d76427
<!doctype html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="resources/intervention.js"></script>
<div id="target" style="padding: 10px; background-color: blue;">
<p>Testing ReportingObserver's |buffered| option.</p>
</div>
<script>
async_test(function(test) {
var observer1 = new ReportingObserver(function(reports, observer) {
test.step(function() {
// Both reports should be observed, since the |buffered| option is set to
// true.
assert_equals(reports.length, 2);
});
test.done();
}, { buffered: true });
// Generate two reports (deprecation and intervention), one before
// and one after calling observe().
causeIntervention();
observer1.observe();
window.webkitStorageInfo;
observer1.disconnect();
}, "Buffered reports observed");
async_test(function(test) {
var observer2 = new ReportingObserver(function(reports, observer) {
test.step(function() {
// Only the second report should be observed, since the |buffered| option
// is set to false by default.
assert_equals(reports.length, 1);
assert_equals(reports[0].type, "deprecation");
assert_equals(reports[0].body.id, "PrefixedWindowURL");
});
test.done();
});
// Generate two reports (deprecation and intervention), one before
// and one after calling observe().
causeIntervention();
observer2.observe();
window.webkitURL; // id = "PrefixedWindowURL"
observer2.disconnect();
}, "Buffered reports not observed");
</script>
......@@ -611,6 +611,7 @@ core_dictionary_idl_files =
"fetch/response_init.idl",
"fileapi/blob_property_bag.idl",
"fileapi/file_property_bag.idl",
"frame/reporting_observer_options.idl",
"frame/scroll_into_view_options.idl",
"frame/scroll_options.idl",
"frame/scroll_to_options.idl",
......
......@@ -771,9 +771,7 @@ void Deprecation::GenerateReport(const LocalFrame* frame, WebFeature feature) {
Report* report = new Report("deprecation", document->Url().GetString(), body);
// Send the deprecation report to any ReportingObservers.
ReportingContext* reporting_context = ReportingContext::From(document);
if (reporting_context->ObserverExists())
reporting_context->QueueReport(report);
ReportingContext::From(document)->QueueReport(report);
// Send the deprecation report to the Reporting API.
mojom::blink::ReportingServiceProxyPtr service;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// https://github.com/WICG/reporting/blob/master/EXPLAINER.md#reportingobserver---observing-reports-from-javascript
// https://wicg.github.io/reporting/#deprecation-report
[
NoInterfaceObject,
......
......@@ -39,9 +39,7 @@ void Intervention::GenerateReport(const LocalFrame* frame,
new Report("intervention", document->Url().GetString(), body);
// Send the intervention report to any ReportingObservers.
ReportingContext* reporting_context = ReportingContext::From(document);
if (reporting_context->ObserverExists())
reporting_context->QueueReport(report);
ReportingContext::From(document)->QueueReport(report);
// Send the intervention report to the Reporting API.
mojom::blink::ReportingServiceProxyPtr service;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// https://github.com/WICG/reporting/blob/master/EXPLAINER.md#reportingobserver---observing-reports-from-javascript
// https://wicg.github.io/reporting/#intervention-report
[
NoInterfaceObject,
......
......@@ -4,8 +4,9 @@
#include "third_party/blink/renderer/core/frame/reporting_context.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/report.h"
#include "third_party/blink/renderer/core/frame/reporting_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
......@@ -30,45 +31,34 @@ ReportingContext* ReportingContext::From(ExecutionContext* context) {
}
void ReportingContext::QueueReport(Report* report) {
if (!ObserverExists())
return;
reports_.push_back(report);
report_buffer_.insert(report);
// When the first report of a batch is queued, make a task to report the whole
// batch (in the queue) to all ReportingObservers.
if (reports_.size() == 1) {
execution_context_->GetTaskRunner(TaskType::kMiscPlatformAPI)
->PostTask(FROM_HERE, WTF::Bind(&ReportingContext::SendReports,
WrapWeakPersistent(this)));
}
}
// Only the most recent 100 reports will remain buffered.
// https://wicg.github.io/reporting/#notify-observers
if (report_buffer_.size() > 100)
report_buffer_.RemoveFirst();
void ReportingContext::SendReports() {
// The reports queued to be sent to callbacks are copied (and cleared) before
// being sent to observers, since additional reports may be queued as a result
// of the callbacks.
auto reports_to_send = reports_;
reports_.clear();
for (auto observer : observers_)
observer->ReportToCallback(reports_to_send);
observer->QueueReport(report);
}
void ReportingContext::RegisterObserver(ReportingObserver* observer) {
observers_.insert(observer);
if (!observer->Buffered())
return;
observer->ClearBuffered();
for (auto report : report_buffer_)
observer->QueueReport(report);
}
void ReportingContext::UnregisterObserver(ReportingObserver* observer) {
observers_.erase(observer);
}
bool ReportingContext::ObserverExists() {
return observers_.size();
}
void ReportingContext::Trace(blink::Visitor* visitor) {
visitor->Trace(observers_);
visitor->Trace(reports_);
visitor->Trace(report_buffer_);
visitor->Trace(execution_context_);
Supplement<ExecutionContext>::Trace(visitor);
}
......
......@@ -30,23 +30,17 @@ class CORE_EXPORT ReportingContext final
// already exist for the given context, one is created.
static ReportingContext* From(ExecutionContext*);
// Queues a report to be reported to all observers.
// Queues a report in all registered observers.
void QueueReport(Report*);
// Sends all queued reports to all observers.
void SendReports();
void RegisterObserver(ReportingObserver*);
void UnregisterObserver(ReportingObserver*);
// Returns whether there is at least one active ReportingObserver.
bool ObserverExists();
void Trace(blink::Visitor*) override;
private:
HeapListHashSet<Member<ReportingObserver>> observers_;
HeapVector<Member<Report>> reports_;
HeapListHashSet<Member<Report>> report_buffer_;
Member<ExecutionContext> execution_context_;
};
......
......@@ -4,26 +4,56 @@
#include "third_party/blink/renderer/core/frame/reporting_observer.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/report.h"
#include "third_party/blink/renderer/core/frame/reporting_context.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/web_task_runner.h"
namespace blink {
ReportingObserver* ReportingObserver::Create(
ExecutionContext* execution_context,
V8ReportingObserverCallback* callback) {
return new ReportingObserver(execution_context, callback);
V8ReportingObserverCallback* callback,
ReportingObserverOptions options) {
return new ReportingObserver(execution_context, callback, options);
}
ReportingObserver::ReportingObserver(ExecutionContext* execution_context,
V8ReportingObserverCallback* callback)
: execution_context_(execution_context), callback_(callback) {}
V8ReportingObserverCallback* callback,
ReportingObserverOptions options)
: execution_context_(execution_context),
callback_(callback),
options_(options) {}
void ReportingObserver::ReportToCallback(
const HeapVector<Member<Report>>& reports) {
callback_->InvokeAndReportException(this, reports, this);
void ReportingObserver::ReportToCallback() {
// The reports queued to be sent to callbacks are copied (and cleared) before
// being sent, since additional reports may be queued as a result of the
// callbacks.
auto reports_to_send = report_queue_;
report_queue_.clear();
callback_->InvokeAndReportException(this, reports_to_send, this);
}
void ReportingObserver::QueueReport(Report* report) {
report_queue_.push_back(report);
// When the first report of a batch is queued, make a task to report the whole
// batch.
if (report_queue_.size() == 1) {
execution_context_->GetTaskRunner(TaskType::kMiscPlatformAPI)
->PostTask(FROM_HERE, WTF::Bind(&ReportingObserver::ReportToCallback,
WrapWeakPersistent(this)));
}
}
bool ReportingObserver::Buffered() {
return options_.buffered();
}
void ReportingObserver::ClearBuffered() {
return options_.setBuffered(false);
}
void ReportingObserver::observe() {
......@@ -37,6 +67,7 @@ void ReportingObserver::disconnect() {
void ReportingObserver::Trace(blink::Visitor* visitor) {
visitor->Trace(execution_context_);
visitor->Trace(callback_);
visitor->Trace(report_queue_);
ScriptWrappable::Trace(visitor);
}
......
......@@ -7,6 +7,8 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_reporting_observer_callback.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/frame/report.h"
#include "third_party/blink/renderer/core/frame/reporting_observer_options.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
......@@ -20,10 +22,21 @@ class CORE_EXPORT ReportingObserver final : public ScriptWrappable {
public:
static ReportingObserver* Create(ExecutionContext*,
V8ReportingObserverCallback*);
V8ReportingObserverCallback*,
ReportingObserverOptions);
// Call the callback with reports.
void ReportToCallback(const HeapVector<Member<Report>>& reports);
// Call the callback with all reports in |report_queue_|.
void ReportToCallback();
// Queues a report to be reported via callback soon (possibly in a batch).
void QueueReport(Report* report);
// Returns the state of the |buffered| option.
bool Buffered();
// Sets the |buffered| option to false. This should be called after queueing
// all buffered reports, so that they are not reported multiple times.
void ClearBuffered();
void observe();
void disconnect();
......@@ -31,10 +44,14 @@ class CORE_EXPORT ReportingObserver final : public ScriptWrappable {
void Trace(blink::Visitor*) override;
private:
explicit ReportingObserver(ExecutionContext*, V8ReportingObserverCallback*);
explicit ReportingObserver(ExecutionContext*,
V8ReportingObserverCallback*,
ReportingObserverOptions);
Member<ExecutionContext> execution_context_;
Member<V8ReportingObserverCallback> callback_;
ReportingObserverOptions options_;
HeapVector<Member<Report>> report_queue_;
};
} // namespace blink
......
......@@ -7,7 +7,7 @@
callback ReportingObserverCallback = void (sequence<Report> reports, ReportingObserver observer);
[
Constructor(ReportingObserverCallback callback),
Constructor(ReportingObserverCallback callback, optional ReportingObserverOptions options),
ConstructorCallWith=ExecutionContext,
RuntimeEnabled=ReportingObserver
] interface ReportingObserver {
......
// Copyright 2018 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.
// https://wicg.github.io/reporting/#dictdef-reportingobserveroptions
dictionary ReportingObserverOptions {
boolean buffered = false;
};
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