Reporting is a central mechanism for sending out-of-band error reports to origins from various other components (e.g. HTTP Public Key Pinning, Interventions, or Content Security Policy could potentially use it).
The parts of it that are exposed to the web platform are specified in three documents:
This document assumes that you’ve read those ones.
Reporting is implemented as part of the network stack in Chromium, such that it can be used by other parts of the network stack (e.g. HPKP) or by non-browser embedders as well as by Chromium.
//net
The top-level class is the ReportingService
. This lives in the
URLRequestContext
, and provides the high-level operations used by
other parts of //net
and other components: queueing reports,
handling configuration headers, clearing browsing data, and so on.
A ReportingPolicy
specifies a number of parameters for the Reporting
API, such as the maximum number of reports and endpoints to queue, the
time interval between delivery attempts, whether or not to persist reports
and clients across network changes, etc. It is used to create a
ReportingService
obeying the specified parameters.
Within ReportingService
lives ReportingContext
, which in turn
contains the inner workings of Reporting, spread across several classes:
The ReportingCache
stores undelivered reports and endpoint
configurations (aka «clients» in the V0 spec, and the named endpoint
per reporting source in the V1 spec).
The ReportingHeaderParser
parses Report-To:
and
`Reporting-Endpoints’ headers and updates the cache accordingly.
The ReportingDeliveryAgent
reads reports from the cache, decides
which endpoints to deliver them to, and attempts to do so. It uses a
couple of helper classes:
The ReportingUploader
does the low-level work of delivering
reports: accepts a URL and JSON from the DeliveryAgent
, creates
a URLRequest
, and parses the result. It also handles sending
CORS preflight requests for cross-origin report uploads.
The ReportingEndpointManager
chooses an endpoint from the
cache when one is requested by the ReportingDeliveryAgent
, and
manages exponential backoff (using BackoffEntry
) for failing
endpoints.
The ReportingGarbageCollector
periodically examines the cache
and removes reports that have remained undelivered for too long, or
that have failed delivery too many times.
The ReportingBrowsingDataRemover
examines the cache upon request
and removes browsing data (reports and endpoints) of selected types
and origins.
The ReportingDelegate
calls upon the NetworkDelegate
(see below)
to check permissions for queueing/sending reports and setting/using
clients.
The ReportingService
is set up in a URLRequestContext
by passing a
ReportingPolicy
to the URLRequestContextBuilder
. This creates a
ReportingService
which is owned by the URLRequestContextStorage
.
Report-To:
headers are processed by an HttpNetworkTransaction
when they
are received, and passed on to the ReportingService
to be added to the
cache.
Reporting-Endpoints:
headers are initially parsed by
PopulateParsedHeaders
, where the raw header data is run through the
Structured Headers parser. If valid, this structure is stored on the network
response until a reporting source can be associated with it, and is then
passed through the ReportingService
to be further validated and added to the
cache.
A reporting source, used only by V1 reports, is a base::UnguessableToken
associated with the document (or worker eventually) which configures reporting
using a Reporting-Endpoints:
header. This same token must be passed into
the ReportingService
when a report is queued for the correct endpoint to be
found. Since the ReportingService
in //net
does not know anything about
documents or workers, it tracks configurations and reports using this source
token. Any object creating such a token is responsible for informing the
ReportingService
when the token will no longer be used (when the document
is destroyed, for instance.) This will cause any outstanding reports for that
token to be sent, and the configuration removed from the cache.
//net
In the network service, a network::NetworkContext
queues reports by getting
the ReportingService
from the URLRequestContext
.
The JavaScript ReportingObserver
interface lives in //third_party/blink/renderer/core/frame/
.
NetworkContext
using a
blink::mojom::ReportingServiceProxy
(implemented in
//content/browser/net/
), which can queue Intervention, Deprecation,
CSP Violation, and Permissions Policy Violation reports.The ChromeNetworkDelegate
in //chrome/browser/net/
checks permissions
for queueing reports and setting/using clients based on whether cookie access
is allowed, and checks permissions for sending reports using a
ReportingPermissionsChecker
, which checks whether the user has allowed
report uploading via the BACKGROUND_SYNC permission.
Cronet can configure «preloaded» Report-To:
headers (as well as Network
Error Logging headers) when initializing a CronetURLRequestContext
, to allow
embedders to collect and send reports before having received a header in an
actual response.
The original V0 reporting API included support for the Report-To
header only,
which configures endpoint groups which apply to an entire origin. This is still
required for Network Error Logging, as those reports are not associated with
any successful document load.
All V0 reports destined for the same endpoint group may be bundled together for delivery, regardless of their source (subject to NIK isolation).
V1 reporting drops the Report-To
header in favor of Reporting-Endpoints
,
which configures named endpoints (single URLs) which are only valid for the
network resource with which the header was sent. (In general, this means
documents and workers, since other resources do not currently generate reports.
Chrome ignores any Reporting-Endpoints
headers on those responses.) The V1 API
does not support multiple weighted URLs for an endpoint, or failover between
them.
V1 reports from the same source may be bundled together in a single delivery,
but must be delivered separtely from other reports, even those coming from a
different Document
object at the same URL.
Chrome cannot yet drop support for NEL, and therefore for the Report-To
header. Until we can, it is possible for reports to be sent to endpoints
configured with either header. NEL reports can only go to those endpoint groups
configured with Report-To
.
To support both mechanisms simultaneously, we do the following:
V1 endpoints are stored in the cache along with V0 endpoint groups. Separate maps are kept of (origin -> endpoint groups) and (source token -> endpoints).
All reports which can be associated with a specific source (currently all reports except for NEL, which requires origin-scoped V0 configuration) must be queued with that source’s reporting source token.
When a report is to be delivered, the ReportingDeliveryAgent
will first
attempt to find a matching V1 endpoint for the source. Only if that is
unsuccessful, because the source is null, or because the named endpoint is not
configured, will it fall back to searching for a matching V0 named endpoint
group.