• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/network_error_logging/network_error_logging_service.h"
6 
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/feature_list.h"
13 #include "base/functional/bind.h"
14 #include "base/json/json_reader.h"
15 #include "base/logging.h"
16 #include "base/memory/raw_ptr.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/rand_util.h"
19 #include "base/time/clock.h"
20 #include "base/time/default_clock.h"
21 #include "base/time/time.h"
22 #include "base/values.h"
23 #include "net/base/features.h"
24 #include "net/base/ip_address.h"
25 #include "net/base/net_errors.h"
26 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
27 #include "net/base/url_util.h"
28 #include "net/log/net_log.h"
29 #include "net/reporting/reporting_service.h"
30 #include "third_party/abseil-cpp/absl/types/optional.h"
31 #include "url/gurl.h"
32 #include "url/origin.h"
33 
34 namespace net {
35 
36 namespace {
37 
38 const int kMaxJsonSize = 16 * 1024;
39 const int kMaxJsonDepth = 4;
40 
41 const char kReportToKey[] = "report_to";
42 const char kMaxAgeKey[] = "max_age";
43 const char kIncludeSubdomainsKey[] = "include_subdomains";
44 const char kSuccessFractionKey[] = "success_fraction";
45 const char kFailureFractionKey[] = "failure_fraction";
46 
47 const char kApplicationPhase[] = "application";
48 const char kConnectionPhase[] = "connection";
49 const char kDnsPhase[] = "dns";
50 
51 const char kDnsAddressChangedType[] = "dns.address_changed";
52 const char kHttpErrorType[] = "http.error";
53 
54 const struct {
55   Error error;
56   const char* phase = nullptr;
57   const char* type = nullptr;
58 } kErrorTypes[] = {
59     {OK, kApplicationPhase, "ok"},
60 
61     // dns.unreachable?
62     {ERR_NAME_NOT_RESOLVED, kDnsPhase, "dns.name_not_resolved"},
63     {ERR_NAME_RESOLUTION_FAILED, kDnsPhase, "dns.failed"},
64     {ERR_DNS_TIMED_OUT, kDnsPhase, "dns.timed_out"},
65     {ERR_DNS_MALFORMED_RESPONSE, kDnsPhase, "dns.protocol"},
66     {ERR_DNS_SERVER_FAILED, kDnsPhase, "dns.server"},
67 
68     {ERR_TIMED_OUT, kConnectionPhase, "tcp.timed_out"},
69     {ERR_CONNECTION_TIMED_OUT, kConnectionPhase, "tcp.timed_out"},
70     {ERR_CONNECTION_CLOSED, kConnectionPhase, "tcp.closed"},
71     {ERR_CONNECTION_RESET, kConnectionPhase, "tcp.reset"},
72     {ERR_CONNECTION_REFUSED, kConnectionPhase, "tcp.refused"},
73     {ERR_CONNECTION_ABORTED, kConnectionPhase, "tcp.aborted"},
74     {ERR_ADDRESS_INVALID, kConnectionPhase, "tcp.address_invalid"},
75     {ERR_ADDRESS_UNREACHABLE, kConnectionPhase, "tcp.address_unreachable"},
76     {ERR_CONNECTION_FAILED, kConnectionPhase, "tcp.failed"},
77 
78     {ERR_SSL_VERSION_OR_CIPHER_MISMATCH, kConnectionPhase,
79      "tls.version_or_cipher_mismatch"},
80     {ERR_BAD_SSL_CLIENT_AUTH_CERT, kConnectionPhase,
81      "tls.bad_client_auth_cert"},
82     {ERR_CERT_INVALID, kConnectionPhase, "tls.cert.invalid"},
83     {ERR_CERT_COMMON_NAME_INVALID, kConnectionPhase, "tls.cert.name_invalid"},
84     {ERR_CERT_DATE_INVALID, kConnectionPhase, "tls.cert.date_invalid"},
85     {ERR_CERT_AUTHORITY_INVALID, kConnectionPhase,
86      "tls.cert.authority_invalid"},
87     {ERR_CERT_REVOKED, kConnectionPhase, "tls.cert.revoked"},
88     {ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN, kConnectionPhase,
89      "tls.cert.pinned_key_not_in_cert_chain"},
90     {ERR_SSL_PROTOCOL_ERROR, kConnectionPhase, "tls.protocol.error"},
91     {ERR_INSECURE_RESPONSE, kConnectionPhase, "tls.failed"},
92     {ERR_SSL_UNRECOGNIZED_NAME_ALERT, kConnectionPhase,
93      "tls.unrecognized_name_alert"},
94     // tls.failed?
95 
96     {ERR_HTTP2_PING_FAILED, kApplicationPhase, "h2.ping_failed"},
97     {ERR_HTTP2_PROTOCOL_ERROR, kConnectionPhase, "h2.protocol.error"},
98 
99     {ERR_QUIC_PROTOCOL_ERROR, kConnectionPhase, "h3.protocol.error"},
100 
101     // http.protocol.error?
102     {ERR_TOO_MANY_REDIRECTS, kApplicationPhase, "http.response.redirect_loop"},
103     {ERR_INVALID_RESPONSE, kApplicationPhase, "http.response.invalid"},
104     {ERR_INVALID_HTTP_RESPONSE, kApplicationPhase, "http.response.invalid"},
105     {ERR_EMPTY_RESPONSE, kApplicationPhase, "http.response.invalid.empty"},
106     {ERR_CONTENT_LENGTH_MISMATCH, kApplicationPhase,
107      "http.response.invalid.content_length_mismatch"},
108     {ERR_INCOMPLETE_CHUNKED_ENCODING, kApplicationPhase,
109      "http.response.invalid.incomplete_chunked_encoding"},
110     {ERR_INVALID_CHUNKED_ENCODING, kApplicationPhase,
111      "http.response.invalid.invalid_chunked_encoding"},
112     {ERR_REQUEST_RANGE_NOT_SATISFIABLE, kApplicationPhase,
113      "http.request.range_not_satisfiable"},
114     {ERR_RESPONSE_HEADERS_TRUNCATED, kApplicationPhase,
115      "http.response.headers.truncated"},
116     {ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, kApplicationPhase,
117      "http.response.headers.multiple_content_disposition"},
118     {ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, kApplicationPhase,
119      "http.response.headers.multiple_content_length"},
120     // http.failed?
121 
122     {ERR_ABORTED, kApplicationPhase, "abandoned"},
123     // unknown?
124 
125     // TODO(juliatuttle): Surely there are more errors we want here.
126 };
127 
GetPhaseAndTypeFromNetError(Error error,std::string * phase_out,std::string * type_out)128 void GetPhaseAndTypeFromNetError(Error error,
129                                  std::string* phase_out,
130                                  std::string* type_out) {
131   for (const auto& error_type : kErrorTypes) {
132     DCHECK(error_type.phase != nullptr);
133     DCHECK(error_type.type != nullptr);
134     if (error_type.error == error) {
135       *phase_out = error_type.phase;
136       *type_out = error_type.type;
137       return;
138     }
139   }
140   *phase_out = IsCertificateError(error) ? kConnectionPhase : kApplicationPhase;
141   *type_out = "unknown";
142 }
143 
IsHttpError(const NetworkErrorLoggingService::RequestDetails & request)144 bool IsHttpError(const NetworkErrorLoggingService::RequestDetails& request) {
145   return request.status_code >= 400 && request.status_code < 600;
146 }
147 
RecordSignedExchangeRequestOutcome(NetworkErrorLoggingService::RequestOutcome outcome)148 void RecordSignedExchangeRequestOutcome(
149     NetworkErrorLoggingService::RequestOutcome outcome) {
150   UMA_HISTOGRAM_ENUMERATION(
151       NetworkErrorLoggingService::kSignedExchangeRequestOutcomeHistogram,
152       outcome);
153 }
154 
155 class NetworkErrorLoggingServiceImpl : public NetworkErrorLoggingService {
156  public:
NetworkErrorLoggingServiceImpl(PersistentNelStore * store)157   explicit NetworkErrorLoggingServiceImpl(PersistentNelStore* store)
158       : store_(store) {
159     if (!PoliciesArePersisted())
160       initialized_ = true;
161   }
162 
~NetworkErrorLoggingServiceImpl()163   ~NetworkErrorLoggingServiceImpl() override {
164     if (PoliciesArePersisted() && initialized_)
165       store_->Flush();
166   }
167 
168   // NetworkErrorLoggingService implementation:
169 
OnHeader(const NetworkAnonymizationKey & network_anonymization_key,const url::Origin & origin,const IPAddress & received_ip_address,const std::string & value)170   void OnHeader(const NetworkAnonymizationKey& network_anonymization_key,
171                 const url::Origin& origin,
172                 const IPAddress& received_ip_address,
173                 const std::string& value) override {
174     // NEL is only available to secure origins, so don't permit insecure origins
175     // to set policies.
176     if (!origin.GetURL().SchemeIsCryptographic())
177       return;
178 
179     base::Time header_received_time = clock_->Now();
180     // base::Unretained is safe because the callback gets stored in
181     // task_backlog_, so the callback will not outlive |*this|.
182     DoOrBacklogTask(base::BindOnce(
183         &NetworkErrorLoggingServiceImpl::DoOnHeader, base::Unretained(this),
184         respect_network_anonymization_key_ ? network_anonymization_key
185                                            : NetworkAnonymizationKey(),
186         origin, received_ip_address, value, header_received_time));
187   }
188 
OnRequest(RequestDetails details)189   void OnRequest(RequestDetails details) override {
190     // This method is only called on secure requests.
191     DCHECK(details.uri.SchemeIsCryptographic());
192 
193     if (!reporting_service_)
194       return;
195 
196     if (!respect_network_anonymization_key_)
197       details.network_anonymization_key = NetworkAnonymizationKey();
198 
199     base::Time request_received_time = clock_->Now();
200     // base::Unretained is safe because the callback gets stored in
201     // task_backlog_, so the callback will not outlive |*this|.
202     DoOrBacklogTask(base::BindOnce(&NetworkErrorLoggingServiceImpl::DoOnRequest,
203                                    base::Unretained(this), std::move(details),
204                                    request_received_time));
205   }
206 
QueueSignedExchangeReport(SignedExchangeReportDetails details)207   void QueueSignedExchangeReport(SignedExchangeReportDetails details) override {
208     if (!reporting_service_) {
209       RecordSignedExchangeRequestOutcome(
210           RequestOutcome::kDiscardedNoReportingService);
211       return;
212     }
213     if (!details.outer_url.SchemeIsCryptographic()) {
214       RecordSignedExchangeRequestOutcome(
215           RequestOutcome::kDiscardedInsecureOrigin);
216       return;
217     }
218 
219     if (!respect_network_anonymization_key_)
220       details.network_anonymization_key = NetworkAnonymizationKey();
221 
222     base::Time request_received_time = clock_->Now();
223     // base::Unretained is safe because the callback gets stored in
224     // task_backlog_, so the callback will not outlive |*this|.
225     DoOrBacklogTask(base::BindOnce(
226         &NetworkErrorLoggingServiceImpl::DoQueueSignedExchangeReport,
227         base::Unretained(this), std::move(details), request_received_time));
228   }
229 
RemoveBrowsingData(const base::RepeatingCallback<bool (const url::Origin &)> & origin_filter)230   void RemoveBrowsingData(
231       const base::RepeatingCallback<bool(const url::Origin&)>& origin_filter)
232       override {
233     // base::Unretained is safe because the callback gets stored in
234     // task_backlog_, so the callback will not outlive |*this|.
235     DoOrBacklogTask(
236         base::BindOnce(&NetworkErrorLoggingServiceImpl::DoRemoveBrowsingData,
237                        base::Unretained(this), origin_filter));
238   }
239 
RemoveAllBrowsingData()240   void RemoveAllBrowsingData() override {
241     // base::Unretained is safe because the callback gets stored in
242     // task_backlog_, so the callback will not outlive |*this|.
243     DoOrBacklogTask(
244         base::BindOnce(&NetworkErrorLoggingServiceImpl::DoRemoveAllBrowsingData,
245                        base::Unretained(this)));
246   }
247 
StatusAsValue() const248   base::Value StatusAsValue() const override {
249     base::Value::Dict dict;
250     base::Value::List policy_list;
251     // We wanted sorted (or at least reproducible) output; luckily, policies_ is
252     // a std::map, and therefore already sorted.
253     for (const auto& key_and_policy : policies_) {
254       const NelPolicyKey& key = key_and_policy.first;
255       const NelPolicy& policy = key_and_policy.second;
256       base::Value::Dict policy_dict;
257       policy_dict.Set("NetworkAnonymizationKey",
258                       key.network_anonymization_key.ToDebugString());
259       policy_dict.Set("origin", key.origin.Serialize());
260       policy_dict.Set("includeSubdomains", policy.include_subdomains);
261       policy_dict.Set("reportTo", policy.report_to);
262       policy_dict.Set("expires", NetLog::TimeToString(policy.expires));
263       policy_dict.Set("successFraction", policy.success_fraction);
264       policy_dict.Set("failureFraction", policy.failure_fraction);
265       policy_list.Append(std::move(policy_dict));
266     }
267     dict.Set("originPolicies", std::move(policy_list));
268     return base::Value(std::move(dict));
269   }
270 
GetPolicyKeysForTesting()271   std::set<NelPolicyKey> GetPolicyKeysForTesting() override {
272     std::set<NelPolicyKey> keys;
273     for (const auto& entry : policies_) {
274       keys.insert(entry.first);
275     }
276     return keys;
277   }
278 
279   NetworkErrorLoggingService::PersistentNelStore*
GetPersistentNelStoreForTesting()280   GetPersistentNelStoreForTesting() override {
281     return store_;
282   }
283 
GetReportingServiceForTesting()284   ReportingService* GetReportingServiceForTesting() override {
285     return reporting_service_;
286   }
287 
288  private:
289   // Map from (NIK, origin) to owned policy.
290   using PolicyMap = std::map<NelPolicyKey, NelPolicy>;
291 
292   // Wildcard policies are policies for which the include_subdomains flag is
293   // true.
294   //
295   // Wildcard policies are accessed by domain name, not full origin. The key
296   // consists of the NetworkAnonymizationKey of the policy, plus a string which
297   // is the host part of the policy's origin.
298   //
299   // Looking up a wildcard policy for a domain yields the wildcard policy with
300   // the longest host part (most specific subdomain) that is a substring of the
301   // domain.
302   //
303   // When multiple policies with the same (NIK, origin.host()) are present, they
304   // are all stored, the policy returned is not well defined.
305   //
306   // Policies in the map are unowned; they are pointers to the original in
307   // the PolicyMap.
308   using WildcardPolicyMap =
309       std::map<WildcardNelPolicyKey, std::set<const NelPolicy*>>;
310 
311   PolicyMap policies_;
312   WildcardPolicyMap wildcard_policies_;
313 
314   // The persistent store in which NEL policies will be stored to disk, if not
315   // null. If |store_| is null, then NEL policies will be in-memory only.
316   // The store is owned by the URLRequestContext because Reporting also needs
317   // access to it.
318   raw_ptr<PersistentNelStore> store_;
319 
320   // Set to true when we have told the store to load NEL policies. This is to
321   // make sure we don't try to load policies multiple times.
322   bool started_loading_policies_ = false;
323 
324   // Set to true when the NEL service has been initialized. Before
325   // initialization is complete, commands to the NEL service (i.e. public
326   // method calls) are stashed away in |task_backlog_|, to be executed once
327   // initialization is complete. Initialization is complete automatically if
328   // there is no PersistentNelStore. If there is a store, then initialization is
329   // complete when the NEL policies have finished being loaded from the store
330   // (either successfully or unsuccessfully).
331   bool initialized_ = false;
332 
333   // Backlog of tasks waiting on initialization.
334   std::vector<base::OnceClosure> task_backlog_;
335 
336   // Set based on network state partitioning status on construction.
337   bool respect_network_anonymization_key_ =
338       NetworkAnonymizationKey::IsPartitioningEnabled();
339 
340   base::WeakPtrFactory<NetworkErrorLoggingServiceImpl> weak_factory_{this};
341 
PoliciesArePersisted() const342   bool PoliciesArePersisted() const { return store_ != nullptr; }
343 
DoOrBacklogTask(base::OnceClosure task)344   void DoOrBacklogTask(base::OnceClosure task) {
345     if (shut_down_)
346       return;
347 
348     FetchAllPoliciesFromStoreIfNecessary();
349 
350     if (!initialized_) {
351       task_backlog_.push_back(std::move(task));
352       return;
353     }
354 
355     std::move(task).Run();
356   }
357 
ExecuteBacklog()358   void ExecuteBacklog() {
359     DCHECK(initialized_);
360 
361     if (shut_down_)
362       return;
363 
364     for (base::OnceClosure& task : task_backlog_) {
365       std::move(task).Run();
366     }
367     task_backlog_.clear();
368   }
369 
DoOnHeader(const NetworkAnonymizationKey & network_anonymization_key,const url::Origin & origin,const IPAddress & received_ip_address,const std::string & value,base::Time header_received_time)370   void DoOnHeader(const NetworkAnonymizationKey& network_anonymization_key,
371                   const url::Origin& origin,
372                   const IPAddress& received_ip_address,
373                   const std::string& value,
374                   base::Time header_received_time) {
375     DCHECK(initialized_);
376 
377     NelPolicy policy;
378     policy.key = NelPolicyKey(network_anonymization_key, origin);
379     policy.received_ip_address = received_ip_address;
380     policy.last_used = header_received_time;
381 
382     if (!ParseHeader(value, clock_->Now(), &policy))
383       return;
384 
385     // Disallow eTLDs from setting include_subdomains policies.
386     if (policy.include_subdomains &&
387         registry_controlled_domains::GetRegistryLength(
388             policy.key.origin.GetURL(),
389             registry_controlled_domains::INCLUDE_UNKNOWN_REGISTRIES,
390             registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES) == 0) {
391       return;
392     }
393 
394     // If a policy for this NelPolicyKey already existed, remove the old policy.
395     auto it = policies_.find(policy.key);
396     if (it != policies_.end())
397       RemovePolicy(it);
398 
399     // A policy's |expires| field is set to a null time if the max_age was 0.
400     // Having a max_age of 0 means that the policy should be removed, so return
401     // here instead of continuing on to inserting the policy.
402     if (policy.expires.is_null())
403       return;
404 
405     AddPolicy(std::move(policy));
406 
407     // Evict policies if the policy limit is exceeded.
408     if (policies_.size() > kMaxPolicies) {
409       RemoveAllExpiredPolicies();
410       while (policies_.size() > kMaxPolicies) {
411         EvictStalestPolicy();
412       }
413     }
414   }
415 
DoOnRequest(RequestDetails details,base::Time request_received_time)416   void DoOnRequest(RequestDetails details, base::Time request_received_time) {
417     DCHECK(reporting_service_);
418     DCHECK(initialized_);
419 
420     if (!respect_network_anonymization_key_)
421       details.network_anonymization_key = NetworkAnonymizationKey();
422 
423     auto report_origin = url::Origin::Create(details.uri);
424     const NelPolicy* policy =
425         FindPolicyForReport(details.network_anonymization_key, report_origin);
426     if (!policy)
427       return;
428 
429     MarkPolicyUsed(policy, request_received_time);
430 
431     Error type = details.type;
432     // It is expected for Reporting uploads to terminate with ERR_ABORTED, since
433     // the ReportingUploader cancels them after receiving the response code and
434     // headers.
435     if (details.reporting_upload_depth > 0 && type == ERR_ABORTED) {
436       // TODO(juliatuttle): Modify ReportingUploader to drain successful uploads
437       // instead of aborting them, so NEL can properly report on aborted
438       // requests.
439       type = OK;
440     }
441 
442     std::string phase_string;
443     std::string type_string;
444     GetPhaseAndTypeFromNetError(type, &phase_string, &type_string);
445 
446     if (IsHttpError(details)) {
447       phase_string = kApplicationPhase;
448       type_string = kHttpErrorType;
449     }
450 
451     // This check would go earlier, but the histogram bucket will be more
452     // meaningful if it only includes reports that otherwise could have been
453     // uploaded.
454     if (details.reporting_upload_depth > kMaxNestedReportDepth)
455       return;
456 
457     // If the server that handled the request is different than the server that
458     // delivered the NEL policy (as determined by their IP address), then we
459     // have to "downgrade" the NEL report, so that it only includes information
460     // about DNS resolution.
461     if (phase_string != kDnsPhase && details.server_ip.IsValid() &&
462         details.server_ip != policy->received_ip_address) {
463       phase_string = kDnsPhase;
464       type_string = kDnsAddressChangedType;
465       details.elapsed_time = base::TimeDelta();
466       details.status_code = 0;
467     }
468 
469     // include_subdomains policies are only allowed to report on DNS resolution
470     // errors.
471     if (phase_string != kDnsPhase &&
472         IsMismatchingSubdomainReport(*policy, report_origin)) {
473       return;
474     }
475 
476     bool success = (type == OK) && !IsHttpError(details);
477     const absl::optional<double> sampling_fraction =
478         SampleAndReturnFraction(*policy, success);
479     if (!sampling_fraction.has_value())
480       return;
481 
482     DVLOG(1) << "Created NEL report (" << type_string
483              << ", status=" << details.status_code
484              << ", depth=" << details.reporting_upload_depth << ") for "
485              << details.uri;
486 
487     // A null reporting source token is used since this report is not associated
488     // with any particular document.
489     reporting_service_->QueueReport(
490         details.uri, absl::nullopt, details.network_anonymization_key,
491         details.user_agent, policy->report_to, kReportType,
492         CreateReportBody(phase_string, type_string, sampling_fraction.value(),
493                          details),
494         details.reporting_upload_depth);
495   }
496 
DoQueueSignedExchangeReport(SignedExchangeReportDetails details,base::Time request_received_time)497   void DoQueueSignedExchangeReport(SignedExchangeReportDetails details,
498                                    base::Time request_received_time) {
499     DCHECK(reporting_service_);
500 
501     const auto report_origin = url::Origin::Create(details.outer_url);
502     const NelPolicy* policy =
503         FindPolicyForReport(details.network_anonymization_key, report_origin);
504     if (!policy) {
505       RecordSignedExchangeRequestOutcome(
506           RequestOutcome::kDiscardedNoOriginPolicy);
507       return;
508     }
509 
510     MarkPolicyUsed(policy, request_received_time);
511 
512     if (IsMismatchingSubdomainReport(*policy, report_origin)) {
513       RecordSignedExchangeRequestOutcome(
514           RequestOutcome::kDiscardedNonDNSSubdomainReport);
515       return;
516     }
517     // Don't send the report when the IP addresses of the server and the policy
518     // don’t match. This case is coverd by OnRequest() while processing the HTTP
519     // response.
520     // This happens if the server has set the NEL policy previously, but doesn't
521     // set the NEL policy for the signed exchange response, and the IP address
522     // has changed due to DNS round robin.
523     if (details.server_ip_address != policy->received_ip_address) {
524       RecordSignedExchangeRequestOutcome(
525           RequestOutcome::kDiscardedIPAddressMismatch);
526       return;
527     }
528     const absl::optional<double> sampling_fraction =
529         SampleAndReturnFraction(*policy, details.success);
530     if (!sampling_fraction.has_value()) {
531       RecordSignedExchangeRequestOutcome(
532           details.success ? RequestOutcome::kDiscardedUnsampledSuccess
533                           : RequestOutcome::kDiscardedUnsampledFailure);
534       return;
535     }
536 
537     // A null reporting source token is used since this report is not associated
538     // with any particular document.
539     reporting_service_->QueueReport(
540         details.outer_url, absl::nullopt, details.network_anonymization_key,
541         details.user_agent, policy->report_to, kReportType,
542         CreateSignedExchangeReportBody(details, sampling_fraction.value()),
543         0 /* depth */);
544     RecordSignedExchangeRequestOutcome(RequestOutcome::kQueued);
545   }
546 
DoRemoveBrowsingData(const base::RepeatingCallback<bool (const url::Origin &)> & origin_filter)547   void DoRemoveBrowsingData(
548       const base::RepeatingCallback<bool(const url::Origin&)>& origin_filter) {
549     DCHECK(initialized_);
550     for (auto it = policies_.begin(); it != policies_.end();) {
551       const NelPolicyKey& key = it->first;
552       // Remove policies matching the filter.
553       if (origin_filter.Run(key.origin)) {
554         it = RemovePolicy(it);
555       } else {
556         ++it;
557       }
558     }
559     if (PoliciesArePersisted())
560       store_->Flush();
561   }
562 
DoRemoveAllBrowsingData()563   void DoRemoveAllBrowsingData() {
564     DCHECK(initialized_);
565     if (PoliciesArePersisted()) {
566       // TODO(chlily): Add a DeleteAllNelPolicies command to PersistentNelStore.
567       for (auto origin_and_policy : policies_) {
568         store_->DeleteNelPolicy(origin_and_policy.second);
569       }
570       store_->Flush();
571     }
572 
573     wildcard_policies_.clear();
574     policies_.clear();
575   }
576 
577   // Returns whether the |json_value| was parsed as a valid header that either
578   // sets a NEL policy (max age > 0) or removes an existing one (max age == 0).
ParseHeader(const std::string & json_value,base::Time now,NelPolicy * policy_out) const579   bool ParseHeader(const std::string& json_value,
580                    base::Time now,
581                    NelPolicy* policy_out) const {
582     DCHECK(policy_out);
583 
584     // JSON is malformed (too large, syntax error, not a dictionary).
585     if (json_value.size() > kMaxJsonSize)
586       return false;
587 
588     absl::optional<base::Value> value =
589         base::JSONReader::Read(json_value, base::JSON_PARSE_RFC, kMaxJsonDepth);
590     if (!value)
591       return false;
592 
593     base::Value::Dict* dict = value->GetIfDict();
594     if (!dict)
595       return false;
596 
597     // Max-Age property is missing or malformed.
598     int max_age_sec = dict->FindInt(kMaxAgeKey).value_or(-1);
599     if (max_age_sec < 0)
600       return false;
601 
602     // Report-To property is missing or malformed.
603     std::string report_to;
604     if (max_age_sec > 0) {
605       std::string* maybe_report_to = dict->FindString(kReportToKey);
606       if (!maybe_report_to)
607         return false;
608       report_to = *maybe_report_to;
609     }
610 
611     // include_subdomains is optional and defaults to false, so it's okay if
612     // GetBoolean fails.
613     bool include_subdomains =
614         dict->FindBool(kIncludeSubdomainsKey).value_or(false);
615 
616     // TODO(chlily): According to the spec we should restrict these sampling
617     // fractions to [0.0, 1.0].
618     // success_fraction is optional and defaults to 0.0, so it's okay if
619     // GetDouble fails.
620     double success_fraction =
621         dict->FindDouble(kSuccessFractionKey).value_or(0.0);
622 
623     // failure_fraction is optional and defaults to 1.0, so it's okay if
624     // GetDouble fails.
625     double failure_fraction =
626         dict->FindDouble(kFailureFractionKey).value_or(1.0);
627 
628     policy_out->report_to = report_to;
629     policy_out->include_subdomains = include_subdomains;
630     policy_out->success_fraction = success_fraction;
631     policy_out->failure_fraction = failure_fraction;
632     policy_out->expires =
633         max_age_sec > 0 ? now + base::Seconds(max_age_sec) : base::Time();
634     return true;
635   }
636 
FindPolicyForReport(const NetworkAnonymizationKey & network_anonymization_key,const url::Origin & report_origin) const637   const NelPolicy* FindPolicyForReport(
638       const NetworkAnonymizationKey& network_anonymization_key,
639       const url::Origin& report_origin) const {
640     DCHECK(initialized_);
641 
642     auto it =
643         policies_.find(NelPolicyKey(network_anonymization_key, report_origin));
644     if (it != policies_.end() && clock_->Now() < it->second.expires)
645       return &it->second;
646 
647     std::string domain = report_origin.host();
648     const NelPolicy* wildcard_policy = nullptr;
649     while (!wildcard_policy && !domain.empty()) {
650       wildcard_policy = FindWildcardPolicy(network_anonymization_key, domain);
651       domain = GetSuperdomain(domain);
652     }
653 
654     return wildcard_policy;
655   }
656 
FindWildcardPolicy(const NetworkAnonymizationKey & network_anonymization_key,const std::string & domain) const657   const NelPolicy* FindWildcardPolicy(
658       const NetworkAnonymizationKey& network_anonymization_key,
659       const std::string& domain) const {
660     DCHECK(!domain.empty());
661 
662     auto it = wildcard_policies_.find(
663         WildcardNelPolicyKey(network_anonymization_key, domain));
664     if (it == wildcard_policies_.end())
665       return nullptr;
666 
667     DCHECK(!it->second.empty());
668 
669     for (const NelPolicy* policy : it->second) {
670       if (clock_->Now() < policy->expires)
671         return policy;
672     }
673 
674     return nullptr;
675   }
676 
677   // There must be no pre-existing policy for |policy.key|. Returns iterator
678   // to the inserted policy.
AddPolicy(NelPolicy policy)679   PolicyMap::iterator AddPolicy(NelPolicy policy) {
680     // If |initialized_| is false, then we are calling this from
681     // OnPoliciesLoaded(), which means we don't want to add the given policy to
682     // the store because we have just loaded it from there.
683     if (PoliciesArePersisted() && initialized_)
684       store_->AddNelPolicy(policy);
685 
686     auto iter_and_result =
687         policies_.insert(std::make_pair(policy.key, std::move(policy)));
688     // TODO(crbug.com/1326282): Change this to a DCHECK when we're sure the bug
689     // is fixed.
690     CHECK(iter_and_result.second);
691 
692     const NelPolicy& inserted_policy = iter_and_result.first->second;
693     MaybeAddWildcardPolicy(inserted_policy.key, &inserted_policy);
694 
695     return iter_and_result.first;
696   }
697 
MaybeAddWildcardPolicy(const NelPolicyKey & origin_key,const NelPolicy * policy)698   void MaybeAddWildcardPolicy(const NelPolicyKey& origin_key,
699                               const NelPolicy* policy) {
700     DCHECK(policy);
701     DCHECK_EQ(policy, &policies_[origin_key]);
702 
703     if (!policy->include_subdomains)
704       return;
705 
706     WildcardNelPolicyKey wildcard_key(origin_key);
707     auto inserted = wildcard_policies_[wildcard_key].insert(policy);
708     DCHECK(inserted.second);
709   }
710 
711   // Removes the policy pointed to by |policy_it|. Invalidates |policy_it|.
712   // Returns the iterator to the next element.
RemovePolicy(PolicyMap::iterator policy_it)713   PolicyMap::iterator RemovePolicy(PolicyMap::iterator policy_it) {
714     DCHECK(policy_it != policies_.end());
715     NelPolicy* policy = &policy_it->second;
716     MaybeRemoveWildcardPolicy(policy);
717 
718     if (PoliciesArePersisted() && initialized_)
719       store_->DeleteNelPolicy(*policy);
720 
721     return policies_.erase(policy_it);
722   }
723 
MaybeRemoveWildcardPolicy(const NelPolicy * policy)724   void MaybeRemoveWildcardPolicy(const NelPolicy* policy) {
725     DCHECK(policy);
726 
727     if (!policy->include_subdomains)
728       return;
729 
730     const NelPolicyKey& origin_key = policy->key;
731     DCHECK_EQ(policy, &policies_[origin_key]);
732 
733     auto wildcard_it =
734         wildcard_policies_.find(WildcardNelPolicyKey(origin_key));
735     DCHECK(wildcard_it != wildcard_policies_.end());
736 
737     size_t erased = wildcard_it->second.erase(policy);
738     DCHECK_EQ(1u, erased);
739     if (wildcard_it->second.empty())
740       wildcard_policies_.erase(wildcard_it);
741   }
742 
MarkPolicyUsed(const NelPolicy * policy,base::Time time_used) const743   void MarkPolicyUsed(const NelPolicy* policy, base::Time time_used) const {
744     policy->last_used = time_used;
745     if (PoliciesArePersisted() && initialized_)
746       store_->UpdateNelPolicyAccessTime(*policy);
747   }
748 
RemoveAllExpiredPolicies()749   void RemoveAllExpiredPolicies() {
750     for (auto it = policies_.begin(); it != policies_.end();) {
751       if (it->second.expires < clock_->Now()) {
752         it = RemovePolicy(it);
753       } else {
754         ++it;
755       }
756     }
757   }
758 
EvictStalestPolicy()759   void EvictStalestPolicy() {
760     PolicyMap::iterator stalest_it = policies_.begin();
761     for (auto it = policies_.begin(); it != policies_.end(); ++it) {
762       if (it->second.last_used < stalest_it->second.last_used)
763         stalest_it = it;
764     }
765 
766     // This should only be called if we have hit the max policy limit, so there
767     // should be at least one policy.
768     DCHECK(stalest_it != policies_.end());
769 
770     RemovePolicy(stalest_it);
771   }
772 
CreateReportBody(const std::string & phase,const std::string & type,double sampling_fraction,const RequestDetails & details)773   static base::Value::Dict CreateReportBody(const std::string& phase,
774                                             const std::string& type,
775                                             double sampling_fraction,
776                                             const RequestDetails& details) {
777     base::Value::Dict body;
778 
779     body.Set(kReferrerKey, details.referrer.spec());
780     body.Set(kSamplingFractionKey, sampling_fraction);
781     body.Set(kServerIpKey, details.server_ip.ToString());
782     body.Set(kProtocolKey, details.protocol);
783     body.Set(kMethodKey, details.method);
784     body.Set(kStatusCodeKey, details.status_code);
785     body.Set(kElapsedTimeKey,
786              static_cast<int>(details.elapsed_time.InMilliseconds()));
787     body.Set(kPhaseKey, phase);
788     body.Set(kTypeKey, type);
789 
790     return body;
791   }
792 
CreateSignedExchangeReportBody(const SignedExchangeReportDetails & details,double sampling_fraction)793   static base::Value::Dict CreateSignedExchangeReportBody(
794       const SignedExchangeReportDetails& details,
795       double sampling_fraction) {
796     base::Value::Dict body;
797     body.Set(kPhaseKey, kSignedExchangePhaseValue);
798     body.Set(kTypeKey, details.type);
799     body.Set(kSamplingFractionKey, sampling_fraction);
800     body.Set(kReferrerKey, details.referrer);
801     body.Set(kServerIpKey, details.server_ip_address.ToString());
802     body.Set(kProtocolKey, details.protocol);
803     body.Set(kMethodKey, details.method);
804     body.Set(kStatusCodeKey, details.status_code);
805     body.Set(kElapsedTimeKey,
806              static_cast<int>(details.elapsed_time.InMilliseconds()));
807 
808     base::Value::Dict sxg_body;
809     sxg_body.Set(kOuterUrlKey, details.outer_url.spec());
810     if (details.inner_url.is_valid())
811       sxg_body.Set(kInnerUrlKey, details.inner_url.spec());
812 
813     base::Value::List cert_url_list;
814     if (details.cert_url.is_valid())
815       cert_url_list.Append(details.cert_url.spec());
816     sxg_body.Set(kCertUrlKey, std::move(cert_url_list));
817     body.Set(kSignedExchangeBodyKey, std::move(sxg_body));
818 
819     return body;
820   }
821 
IsMismatchingSubdomainReport(const NelPolicy & policy,const url::Origin & report_origin) const822   bool IsMismatchingSubdomainReport(const NelPolicy& policy,
823                                     const url::Origin& report_origin) const {
824     return policy.include_subdomains && (policy.key.origin != report_origin);
825   }
826 
827   // Returns a valid value of matching fraction iff the event should be sampled.
SampleAndReturnFraction(const NelPolicy & policy,bool success) const828   absl::optional<double> SampleAndReturnFraction(const NelPolicy& policy,
829                                                  bool success) const {
830     const double sampling_fraction =
831         success ? policy.success_fraction : policy.failure_fraction;
832 
833     // Sampling fractions are often either 0.0 or 1.0, so in those cases we
834     // can avoid having to call RandDouble().
835     if (sampling_fraction <= 0.0)
836       return absl::nullopt;
837     if (sampling_fraction >= 1.0)
838       return sampling_fraction;
839 
840     if (base::RandDouble() >= sampling_fraction)
841       return absl::nullopt;
842     return sampling_fraction;
843   }
844 
FetchAllPoliciesFromStoreIfNecessary()845   void FetchAllPoliciesFromStoreIfNecessary() {
846     if (!PoliciesArePersisted() || started_loading_policies_)
847       return;
848 
849     started_loading_policies_ = true;
850     FetchAllPoliciesFromStore();
851   }
852 
FetchAllPoliciesFromStore()853   void FetchAllPoliciesFromStore() {
854     DCHECK(PoliciesArePersisted());
855     DCHECK(!initialized_);
856 
857     store_->LoadNelPolicies(
858         base::BindOnce(&NetworkErrorLoggingServiceImpl::OnPoliciesLoaded,
859                        weak_factory_.GetWeakPtr()));
860   }
861 
862   // This is called when loading from the store is complete, regardless of
863   // success or failure.
864   // DB initialization may have failed, in which case we will receive an empty
865   // vector from the PersistentNelStore. This is indistinguishable from a
866   // successful load that happens to not yield any policies, but in
867   // either case we still want to go through the task backlog.
OnPoliciesLoaded(std::vector<NelPolicy> loaded_policies)868   void OnPoliciesLoaded(std::vector<NelPolicy> loaded_policies) {
869     DCHECK(PoliciesArePersisted());
870     DCHECK(!initialized_);
871 
872     // TODO(chlily): Toss any expired policies we encounter.
873     for (NelPolicy& policy : loaded_policies) {
874       if (policies_.find(policy.key) == policies_.end()) {
875         AddPolicy(std::move(policy));
876       }
877     }
878     initialized_ = true;
879     ExecuteBacklog();
880   }
881 };
882 
883 }  // namespace
884 
885 NetworkErrorLoggingService::NelPolicyKey::NelPolicyKey() = default;
886 
NelPolicyKey(const NetworkAnonymizationKey & network_anonymization_key,const url::Origin & origin)887 NetworkErrorLoggingService::NelPolicyKey::NelPolicyKey(
888     const NetworkAnonymizationKey& network_anonymization_key,
889     const url::Origin& origin)
890     : network_anonymization_key(network_anonymization_key), origin(origin) {}
891 
892 NetworkErrorLoggingService::NelPolicyKey::NelPolicyKey(
893     const NelPolicyKey& other) = default;
894 
operator <(const NelPolicyKey & other) const895 bool NetworkErrorLoggingService::NelPolicyKey::operator<(
896     const NelPolicyKey& other) const {
897   return std::tie(network_anonymization_key, origin) <
898          std::tie(other.network_anonymization_key, other.origin);
899 }
900 
operator ==(const NelPolicyKey & other) const901 bool NetworkErrorLoggingService::NelPolicyKey::operator==(
902     const NelPolicyKey& other) const {
903   return std::tie(network_anonymization_key, origin) ==
904          std::tie(other.network_anonymization_key, other.origin);
905 }
906 
operator !=(const NelPolicyKey & other) const907 bool NetworkErrorLoggingService::NelPolicyKey::operator!=(
908     const NelPolicyKey& other) const {
909   return !(*this == other);
910 }
911 
912 NetworkErrorLoggingService::NelPolicyKey::~NelPolicyKey() = default;
913 
914 NetworkErrorLoggingService::WildcardNelPolicyKey::WildcardNelPolicyKey() =
915     default;
916 
WildcardNelPolicyKey(const NetworkAnonymizationKey & network_anonymization_key,const std::string & domain)917 NetworkErrorLoggingService::WildcardNelPolicyKey::WildcardNelPolicyKey(
918     const NetworkAnonymizationKey& network_anonymization_key,
919     const std::string& domain)
920     : network_anonymization_key(network_anonymization_key), domain(domain) {}
921 
WildcardNelPolicyKey(const NelPolicyKey & origin_key)922 NetworkErrorLoggingService::WildcardNelPolicyKey::WildcardNelPolicyKey(
923     const NelPolicyKey& origin_key)
924     : WildcardNelPolicyKey(origin_key.network_anonymization_key,
925                            origin_key.origin.host()) {}
926 
927 NetworkErrorLoggingService::WildcardNelPolicyKey::WildcardNelPolicyKey(
928     const WildcardNelPolicyKey& other) = default;
929 
operator <(const WildcardNelPolicyKey & other) const930 bool NetworkErrorLoggingService::WildcardNelPolicyKey::operator<(
931     const WildcardNelPolicyKey& other) const {
932   return std::tie(network_anonymization_key, domain) <
933          std::tie(other.network_anonymization_key, other.domain);
934 }
935 
936 NetworkErrorLoggingService::WildcardNelPolicyKey::~WildcardNelPolicyKey() =
937     default;
938 
939 NetworkErrorLoggingService::NelPolicy::NelPolicy() = default;
940 
941 NetworkErrorLoggingService::NelPolicy::NelPolicy(const NelPolicy& other) =
942     default;
943 
944 NetworkErrorLoggingService::NelPolicy::~NelPolicy() = default;
945 
946 NetworkErrorLoggingService::RequestDetails::RequestDetails() = default;
947 
948 NetworkErrorLoggingService::RequestDetails::RequestDetails(
949     const RequestDetails& other) = default;
950 
951 NetworkErrorLoggingService::RequestDetails::~RequestDetails() = default;
952 
953 NetworkErrorLoggingService::SignedExchangeReportDetails::
954     SignedExchangeReportDetails() = default;
955 
956 NetworkErrorLoggingService::SignedExchangeReportDetails::
957     SignedExchangeReportDetails(const SignedExchangeReportDetails& other) =
958         default;
959 
960 NetworkErrorLoggingService::SignedExchangeReportDetails::
961     ~SignedExchangeReportDetails() = default;
962 
963 const char NetworkErrorLoggingService::kHeaderName[] = "NEL";
964 
965 const char NetworkErrorLoggingService::kReportType[] = "network-error";
966 
967 const char
968     NetworkErrorLoggingService::kSignedExchangeRequestOutcomeHistogram[] =
969         "Net.NetworkErrorLogging.SignedExchangeRequestOutcome";
970 
971 // Allow NEL reports on regular requests, plus NEL reports on Reporting uploads
972 // containing only regular requests, but do not allow NEL reports on Reporting
973 // uploads containing Reporting uploads.
974 //
975 // This prevents origins from building purposefully-broken Reporting endpoints
976 // that generate new NEL reports to bypass the age limit on Reporting reports.
977 const int NetworkErrorLoggingService::kMaxNestedReportDepth = 1;
978 
979 const char NetworkErrorLoggingService::kReferrerKey[] = "referrer";
980 const char NetworkErrorLoggingService::kSamplingFractionKey[] =
981     "sampling_fraction";
982 const char NetworkErrorLoggingService::kServerIpKey[] = "server_ip";
983 const char NetworkErrorLoggingService::kProtocolKey[] = "protocol";
984 const char NetworkErrorLoggingService::kMethodKey[] = "method";
985 const char NetworkErrorLoggingService::kStatusCodeKey[] = "status_code";
986 const char NetworkErrorLoggingService::kElapsedTimeKey[] = "elapsed_time";
987 const char NetworkErrorLoggingService::kPhaseKey[] = "phase";
988 const char NetworkErrorLoggingService::kTypeKey[] = "type";
989 
990 const char NetworkErrorLoggingService::kSignedExchangePhaseValue[] = "sxg";
991 const char NetworkErrorLoggingService::kSignedExchangeBodyKey[] = "sxg";
992 const char NetworkErrorLoggingService::kOuterUrlKey[] = "outer_url";
993 const char NetworkErrorLoggingService::kInnerUrlKey[] = "inner_url";
994 const char NetworkErrorLoggingService::kCertUrlKey[] = "cert_url";
995 
996 // See also: max number of Reporting endpoints specified in ReportingPolicy.
997 const size_t NetworkErrorLoggingService::kMaxPolicies = 1000u;
998 
999 // static
Create(PersistentNelStore * store)1000 std::unique_ptr<NetworkErrorLoggingService> NetworkErrorLoggingService::Create(
1001     PersistentNelStore* store) {
1002   return std::make_unique<NetworkErrorLoggingServiceImpl>(store);
1003 }
1004 
1005 NetworkErrorLoggingService::~NetworkErrorLoggingService() = default;
1006 
SetReportingService(ReportingService * reporting_service)1007 void NetworkErrorLoggingService::SetReportingService(
1008     ReportingService* reporting_service) {
1009   DCHECK(!reporting_service_);
1010   reporting_service_ = reporting_service;
1011 }
1012 
OnShutdown()1013 void NetworkErrorLoggingService::OnShutdown() {
1014   shut_down_ = true;
1015   reporting_service_ = nullptr;
1016 }
1017 
SetClockForTesting(const base::Clock * clock)1018 void NetworkErrorLoggingService::SetClockForTesting(const base::Clock* clock) {
1019   clock_ = clock;
1020 }
1021 
StatusAsValue() const1022 base::Value NetworkErrorLoggingService::StatusAsValue() const {
1023   NOTIMPLEMENTED();
1024   return base::Value();
1025 }
1026 
1027 std::set<NetworkErrorLoggingService::NelPolicyKey>
GetPolicyKeysForTesting()1028 NetworkErrorLoggingService::GetPolicyKeysForTesting() {
1029   NOTIMPLEMENTED();
1030   return std::set<NelPolicyKey>();
1031 }
1032 
1033 NetworkErrorLoggingService::PersistentNelStore*
GetPersistentNelStoreForTesting()1034 NetworkErrorLoggingService::GetPersistentNelStoreForTesting() {
1035   NOTIMPLEMENTED();
1036   return nullptr;
1037 }
1038 
GetReportingServiceForTesting()1039 ReportingService* NetworkErrorLoggingService::GetReportingServiceForTesting() {
1040   NOTIMPLEMENTED();
1041   return nullptr;
1042 }
1043 
NetworkErrorLoggingService()1044 NetworkErrorLoggingService::NetworkErrorLoggingService()
1045     : clock_(base::DefaultClock::GetInstance()) {}
1046 
1047 }  // namespace net
1048