README.md
1# Reporting
2
3Reporting is a central mechanism for sending out-of-band error reports
4to origins from various other components (e.g. HTTP Public Key Pinning,
5Interventions, or Content Security Policy could potentially use it).
6
7The parts of it that are exposed to the web platform are specified in three
8documents:
9 * The original API implemented in Chrome (Reporting V0) can be found at
10 [https://www.w3.org/TR/2018/WD-reporting-1-20180925/].
11 * The newer API is split into two parts. Document and worker-level reporting
12 (Reporting V1) is specified in the [draft reporting spec]
13 (https://w3c.github.io/reporting/), while Network-level reporting is
14 specified in the [draft network reporting spec]
15 (https://w3c.github.io/reporting/network-reporting.html).
16
17This document assumes that you've read those ones.
18
19## Reporting in Chromium
20
21Reporting is implemented as part of the network stack in Chromium, such
22that it can be used by other parts of the network stack (e.g. HPKP) or
23by non-browser embedders as well as by Chromium.
24
25### Inside `//net`
26
27* The top-level class is the *`ReportingService`*. This lives in the
28 `URLRequestContext`, and provides the high-level operations used by
29 other parts of `//net` and other components: queueing reports,
30 handling configuration headers, clearing browsing data, and so on.
31
32 * A *`ReportingPolicy`* specifies a number of parameters for the Reporting
33 API, such as the maximum number of reports and endpoints to queue, the
34 time interval between delivery attempts, whether or not to persist reports
35 and clients across network changes, etc. It is used to create a
36 `ReportingService` obeying the specified parameters.
37
38 * Within `ReportingService` lives *`ReportingContext`*, which in turn
39 contains the inner workings of Reporting, spread across several classes:
40
41 * The *`ReportingCache`* stores undelivered reports and endpoint
42 configurations (aka "clients" in the V0 spec, and the named endpoint
43 per reporting source in the V1 spec).
44
45 * The *`ReportingHeaderParser`* parses `Report-To:` and
46 `Reporting-Endpoints' headers and updates the cache accordingly.
47
48 * The *`ReportingDeliveryAgent`* reads reports from the cache, decides
49 which endpoints to deliver them to, and attempts to do so. It uses a
50 couple of helper classes:
51
52 * The *`ReportingUploader`* does the low-level work of delivering
53 reports: accepts a URL and JSON from the `DeliveryAgent`, creates
54 a `URLRequest`, and parses the result. It also handles sending
55 CORS preflight requests for cross-origin report uploads.
56
57 * The *`ReportingEndpointManager`* chooses an endpoint from the
58 cache when one is requested by the `ReportingDeliveryAgent`, and
59 manages exponential backoff (using `BackoffEntry`) for failing
60 endpoints.
61
62 * The *`ReportingGarbageCollector`* periodically examines the cache
63 and removes reports that have remained undelivered for too long, or
64 that have failed delivery too many times.
65
66 * The *`ReportingBrowsingDataRemover`* examines the cache upon request
67 and removes browsing data (reports and endpoints) of selected types
68 and origins.
69
70 * The *`ReportingDelegate`* calls upon the `NetworkDelegate` (see below)
71 to check permissions for queueing/sending reports and setting/using
72 clients.
73
74* The `ReportingService` is set up in a `URLRequestContext` by passing a
75 `ReportingPolicy` to the `URLRequestContextBuilder`. This creates a
76 `ReportingService` which is owned by the `URLRequestContext`.
77
78* `Report-To:` headers are processed by an `HttpNetworkTransaction` when they
79 are received, and passed on to the `ReportingService` to be added to the
80 cache.
81
82* `Reporting-Endpoints:` headers are initially parsed by
83 `PopulateParsedHeaders`, where the raw header data is run through the
84 Structured Headers parser. If valid, this structure is stored on the network
85 response until a reporting source can be associated with it, and is then
86 passed through the `ReportingService` to be further validated and added to the
87 cache.
88
89* A reporting source, used only by V1 reports, is a `base::UnguessableToken`
90 associated with the document (or worker eventually) which configures reporting
91 using a `Reporting-Endpoints:` header. This same token must be passed into
92 the `ReportingService` when a report is queued for the correct endpoint to be
93 found. Since the `ReportingService` in `//net` does not know anything about
94 documents or workers, it tracks configurations and reports using this source
95 token. Any object creating such a token is responsible for informing the
96 `ReportingService` when the token will no longer be used (when the document
97 is destroyed, for instance.) This will cause any outstanding reports for that
98 token to be sent, and the configuration removed from the cache.
99
100### Outside `//net`
101
102* In the network service, a `network::NetworkContext` queues reports by getting
103 the `ReportingService` from the `URLRequestContext`.
104
105* The JavaScript [ReportingObserver](https://w3c.github.io/reporting/#observers)
106 interface lives [in `//third_party/blink/renderer/core/frame/`][1].
107
108 * It queues reports via the `NetworkContext` using a
109 `blink::mojom::ReportingServiceProxy` (implemented [in
110 `//content/browser/network/`][2]), which can queue Intervention, Deprecation,
111 CSP Violation, and Permissions Policy Violation reports.
112
113* The `ChromeNetworkDelegate` [in `//chrome/browser/net/`][3] checks permissions
114 for queueing reports and setting/using clients based on whether cookie access
115 is allowed, and checks permissions for sending reports using a
116 `ReportingPermissionsChecker`, which checks whether the user has allowed
117 report uploading via the BACKGROUND_SYNC permission.
118
119* Cronet can configure "preloaded" `Report-To:` headers (as well as Network
120 Error Logging headers) when initializing a `CronetURLRequestContext`, to allow
121 embedders to collect and send reports before having received a header in an
122 actual response.
123
124 * This functionality is tested on Android by way of sending Network Error
125 Logging reports [in the Cronet Java tests][4].
126
127## Differences between V0 and V1 reporting
128
129The original V0 reporting API included support for the `Report-To` header only,
130which configures endpoint groups which apply to an entire origin. This is still
131required for Network Error Logging, as those reports are not associated with
132any successful document load.
133
134All V0 reports destined for the same endpoint group may be bundled together for
135delivery, regardless of their source (subject to NAK isolation).
136
137V1 reporting drops the `Report-To` header in favor of `Reporting-Endpoints`,
138which configures named endpoints (single URLs) which are only valid for the
139network resource with which the header was sent. (In general, this means
140documents and workers, since other resources do not currently generate reports.
141Chrome ignores any `Reporting-Endpoints` headers on those responses.) The V1 API
142does not support multiple weighted URLs for an endpoint, or failover between
143them.
144
145V1 reports from the same source may be bundled together in a single delivery,
146but must be delivered separtely from other reports, even those coming from a
147different `Document` object at the same URL.
148
149## Supporting both V0 and V1 reporting in the same codebase
150
151Chrome cannot yet drop support for NEL, and therefore for the `Report-To`
152header. Until we can, it is possible for reports to be sent to endpoints
153configured with either header. NEL reports can only go to those endpoint groups
154configured with `Report-To`.
155
156To support both mechanisms simultaneously, we do the following:
157
158* V1 endpoints are stored in the cache along with V0 endpoint groups. Separate
159 maps are kept of (origin -> endpoint groups) and (source token -> endpoints).
160
161* All reports which can be associated with a specific source (currently all
162 reports except for NEL, which requires origin-scoped V0 configuration) must be
163 queued with that source's reporting source token.
164
165* When a report is to be delivered, the `ReportingDeliveryAgent` will first
166 attempt to find a matching V1 endpoint for the source. Only if that is
167 unsuccessful, because the source is null, or because the named endpoint is not
168 configured, will it fall back to searching for a matching V0 named endpoint
169 group.
170
171[1]: https://chromium.googlesource.com/chromium/src/+/HEAD/third_party/blink/renderer/core/frame/reporting_observer.h
172[2]: https://chromium.googlesource.com/chromium/src/+/HEAD/content/browser/network/reporting_service_proxy.cc
173[3]: https://chromium.googlesource.com/chromium/src/+/HEAD/chrome/browser/net/chrome_network_delegate.h
174[4]: https://chromium.googlesource.com/chromium/src/+/HEAD/components/cronet/android/test/javatests/src/org/chromium/net/NetworkErrorLoggingTest.java
175