blob: 7c6217e8cf55ee6f91e3a973274773c54d017873 [file] [log] [blame]
[email protected]45de676a2014-03-18 23:52:021// Copyright 2014 The Chromium Authors. All rights reserved.
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 "components/domain_reliability/context.h"
6
7#include <algorithm>
dcheng51606352015-12-26 21:16:238#include <utility>
[email protected]45de676a2014-03-18 23:52:029
10#include "base/bind.h"
11#include "base/json/json_writer.h"
12#include "base/logging.h"
asvitkine30330812016-08-30 04:01:0813#include "base/metrics/histogram_macros.h"
[email protected]d9df3b82014-04-08 23:44:0014#include "base/metrics/sparse_histogram.h"
ttuttleccc4ffa2015-12-10 20:08:4615#include "base/rand_util.h"
[email protected]45de676a2014-03-18 23:52:0216#include "base/values.h"
[email protected]bda8e362014-03-24 18:21:0317#include "components/domain_reliability/dispatcher.h"
[email protected]b5c2b742014-06-14 22:21:4218#include "components/domain_reliability/uploader.h"
19#include "components/domain_reliability/util.h"
[email protected]d9df3b82014-04-08 23:44:0020#include "net/base/net_errors.h"
[email protected]45de676a2014-03-18 23:52:0221#include "net/url_request/url_request_context_getter.h"
22
23using base::DictionaryValue;
24using base::ListValue;
25using base::Value;
26
27namespace domain_reliability {
28
ttuttle42144d8a2015-12-01 23:57:3729// static
30const int DomainReliabilityContext::kMaxUploadDepthToSchedule = 1;
31
ttuttleca1ac312015-03-12 17:07:0032DomainReliabilityContext::Factory::~Factory() {
33}
34
[email protected]84d2a492014-05-09 22:18:5035// static
36const size_t DomainReliabilityContext::kMaxQueuedBeacons = 150;
[email protected]45de676a2014-03-18 23:52:0237
38DomainReliabilityContext::DomainReliabilityContext(
39 MockableTime* time,
[email protected]bda8e362014-03-24 18:21:0340 const DomainReliabilityScheduler::Params& scheduler_params,
[email protected]84d2a492014-05-09 22:18:5041 const std::string& upload_reporter_string,
ttuttle743f4ae2014-11-04 20:22:3242 const base::TimeTicks* last_network_change_time,
Julia Tuttle30b169652017-10-16 20:19:0843 const UploadAllowedCallback& upload_allowed_callback,
[email protected]bda8e362014-03-24 18:21:0344 DomainReliabilityDispatcher* dispatcher,
45 DomainReliabilityUploader* uploader,
dcheng04a35cd2016-04-22 15:07:2446 std::unique_ptr<const DomainReliabilityConfig> config)
dcheng51606352015-12-26 21:16:2347 : config_(std::move(config)),
[email protected]45de676a2014-03-18 23:52:0248 time_(time),
[email protected]84d2a492014-05-09 22:18:5049 upload_reporter_string_(upload_reporter_string),
50 scheduler_(time,
51 config_->collectors.size(),
52 scheduler_params,
[email protected]bda8e362014-03-24 18:21:0353 base::Bind(&DomainReliabilityContext::ScheduleUpload,
54 base::Unretained(this))),
55 dispatcher_(dispatcher),
56 uploader_(uploader),
[email protected]f3589bf2014-07-31 03:54:1657 uploading_beacons_size_(0),
ttuttle743f4ae2014-11-04 20:22:3258 last_network_change_time_(last_network_change_time),
Julia Tuttle30b169652017-10-16 20:19:0859 upload_allowed_callback_(upload_allowed_callback),
dcheng51606352015-12-26 21:16:2360 weak_factory_(this) {}
[email protected]45de676a2014-03-18 23:52:0261
ttuttleccdd6cc52015-11-22 06:09:4062DomainReliabilityContext::~DomainReliabilityContext() {
63 ClearBeacons();
64}
[email protected]45de676a2014-03-18 23:52:0265
Julia Tuttle17d6a412017-11-14 18:18:4666void DomainReliabilityContext::OnBeacon(
dcheng04a35cd2016-04-22 15:07:2467 std::unique_ptr<DomainReliabilityBeacon> beacon) {
ttuttleccdd6cc52015-11-22 06:09:4068 bool success = (beacon->status == "ok");
zhongyi93fa5a92016-03-14 18:10:5769 double sample_rate = beacon->details.quic_port_migration_detected
70 ? 1.0
71 : config().GetSampleRate(success);
Julia Tuttle17d6a412017-11-14 18:18:4672 if (base::RandDouble() >= sample_rate)
73 return;
ttuttleccc4ffa2015-12-10 20:08:4674 beacon->sample_rate = sample_rate;
[email protected]d9df3b82014-04-08 23:44:0075
ttuttled89375a2015-12-09 20:54:5776 // Allow beacons about reports, but don't schedule an upload for more than
77 // one layer of recursion, to avoid infinite report loops.
ttuttle42144d8a2015-12-01 23:57:3778 if (beacon->upload_depth <= kMaxUploadDepthToSchedule)
79 scheduler_.OnBeaconAdded();
avi12ce31d2016-08-30 16:38:0580 beacons_.push_back(std::move(beacon));
ttuttleccc4ffa2015-12-10 20:08:4681 bool should_evict = beacons_.size() > kMaxQueuedBeacons;
82 if (should_evict)
ttuttleccdd6cc52015-11-22 06:09:4083 RemoveOldestBeacon();
[email protected]45de676a2014-03-18 23:52:0284}
85
[email protected]9b2034032014-05-11 18:10:3186void DomainReliabilityContext::ClearBeacons() {
[email protected]f3589bf2014-07-31 03:54:1687 beacons_.clear();
88 uploading_beacons_size_ = 0;
[email protected]9b2034032014-05-11 18:10:3189}
90
dcheng04a35cd2016-04-22 15:07:2491std::unique_ptr<Value> DomainReliabilityContext::GetWebUIData() const {
ttuttleccdd6cc52015-11-22 06:09:4092 DictionaryValue* context_value = new DictionaryValue();
[email protected]a6093f412014-07-10 00:57:0993
ttuttleccdd6cc52015-11-22 06:09:4094 context_value->SetString("origin", config().origin.spec());
[email protected]f3589bf2014-07-31 03:54:1695 context_value->SetInteger("beacon_count", static_cast<int>(beacons_.size()));
[email protected]a6093f412014-07-10 00:57:0996 context_value->SetInteger("uploading_beacon_count",
[email protected]f3589bf2014-07-31 03:54:1697 static_cast<int>(uploading_beacons_size_));
[email protected]a6093f412014-07-10 00:57:0998 context_value->Set("scheduler", scheduler_.GetWebUIData());
99
dcheng04a35cd2016-04-22 15:07:24100 return std::unique_ptr<Value>(context_value);
[email protected]a6093f412014-07-10 00:57:09101}
102
[email protected]f3589bf2014-07-31 03:54:16103void DomainReliabilityContext::GetQueuedBeaconsForTesting(
ttuttleccdd6cc52015-11-22 06:09:40104 std::vector<const DomainReliabilityBeacon*>* beacons_out) const {
105 DCHECK(this);
106 DCHECK(beacons_out);
avi12ce31d2016-08-30 16:38:05107 beacons_out->clear();
108 for (const auto& beacon : beacons_)
109 beacons_out->push_back(beacon.get());
[email protected]f3589bf2014-07-31 03:54:16110}
111
[email protected]bda8e362014-03-24 18:21:03112void DomainReliabilityContext::ScheduleUpload(
113 base::TimeDelta min_delay,
114 base::TimeDelta max_delay) {
115 dispatcher_->ScheduleTask(
Julia Tuttle30b169652017-10-16 20:19:08116 base::Bind(&DomainReliabilityContext::CallUploadAllowedCallback,
117 weak_factory_.GetWeakPtr()),
118 min_delay, max_delay);
119}
120
121void DomainReliabilityContext::CallUploadAllowedCallback() {
122 RemoveExpiredBeacons();
123 if (beacons_.empty())
124 return;
125
126 upload_allowed_callback_.Run(
127 config().origin,
tzik2bcf8e42018-07-31 11:22:15128 base::BindOnce(&DomainReliabilityContext::OnUploadAllowedCallbackComplete,
129 weak_factory_.GetWeakPtr()));
Julia Tuttle30b169652017-10-16 20:19:08130}
131
132void DomainReliabilityContext::OnUploadAllowedCallbackComplete(bool allowed) {
133 if (allowed)
134 StartUpload();
[email protected]bda8e362014-03-24 18:21:03135}
136
137void DomainReliabilityContext::StartUpload() {
juliatuttle619e3562016-11-04 23:10:46138 RemoveExpiredBeacons();
139 if (beacons_.empty())
140 return;
141
[email protected]bda8e362014-03-24 18:21:03142 MarkUpload();
143
[email protected]84d2a492014-05-09 22:18:50144 size_t collector_index = scheduler_.OnUploadStart();
ttuttleccdd6cc52015-11-22 06:09:40145 const GURL& collector_url = *config().collectors[collector_index];
146
ttuttle42144d8a2015-12-01 23:57:37147 DCHECK(upload_time_.is_null());
148 upload_time_ = time_->NowTicks();
149 std::string report_json = "{}";
150 int max_upload_depth = -1;
151 bool wrote = base::JSONWriter::Write(
152 *CreateReport(upload_time_,
153 collector_url,
154 &max_upload_depth),
155 &report_json);
156 DCHECK(wrote);
157 DCHECK_NE(-1, max_upload_depth);
[email protected]bda8e362014-03-24 18:21:03158
159 uploader_->UploadReport(
ttuttle42144d8a2015-12-01 23:57:37160 report_json,
161 max_upload_depth,
162 collector_url,
163 base::Bind(
164 &DomainReliabilityContext::OnUploadComplete,
165 weak_factory_.GetWeakPtr()));
[email protected]bda8e362014-03-24 18:21:03166}
167
ttuttle280a73d2014-11-13 21:38:04168void DomainReliabilityContext::OnUploadComplete(
169 const DomainReliabilityUploader::UploadResult& result) {
170 if (result.is_success())
[email protected]bda8e362014-03-24 18:21:03171 CommitUpload();
[email protected]f3589bf2014-07-31 03:54:16172 else
173 RollbackUpload();
ttuttle17d13022015-02-11 22:17:35174 base::TimeTicks first_beacon_time = scheduler_.first_beacon_time();
ttuttle280a73d2014-11-13 21:38:04175 scheduler_.OnUploadComplete(result);
176 UMA_HISTOGRAM_BOOLEAN("DomainReliability.UploadSuccess",
177 result.is_success());
ttuttle17d13022015-02-11 22:17:35178 base::TimeTicks now = time_->NowTicks();
179 UMA_HISTOGRAM_LONG_TIMES("DomainReliability.UploadLatency",
180 now - first_beacon_time);
[email protected]d9df3b82014-04-08 23:44:00181 DCHECK(!upload_time_.is_null());
182 UMA_HISTOGRAM_MEDIUM_TIMES("DomainReliability.UploadDuration",
ttuttle17d13022015-02-11 22:17:35183 now - upload_time_);
[email protected]d9df3b82014-04-08 23:44:00184 last_upload_time_ = upload_time_;
185 upload_time_ = base::TimeTicks();
[email protected]bda8e362014-03-24 18:21:03186}
187
dcheng04a35cd2016-04-22 15:07:24188std::unique_ptr<const Value> DomainReliabilityContext::CreateReport(
ttuttleccdd6cc52015-11-22 06:09:40189 base::TimeTicks upload_time,
ttuttle42144d8a2015-12-01 23:57:37190 const GURL& collector_url,
191 int* max_upload_depth_out) const {
192 int max_upload_depth = 0;
193
dcheng04a35cd2016-04-22 15:07:24194 std::unique_ptr<ListValue> beacons_value(new ListValue());
avi12ce31d2016-08-30 16:38:05195 for (const auto& beacon : beacons_) {
ttuttleccdd6cc52015-11-22 06:09:40196 beacons_value->Append(beacon->ToValue(upload_time,
197 *last_network_change_time_,
198 collector_url,
199 config().path_prefixes));
ttuttle42144d8a2015-12-01 23:57:37200 if (beacon->upload_depth > max_upload_depth)
201 max_upload_depth = beacon->upload_depth;
[email protected]90c03332014-05-16 17:35:18202 }
[email protected]45de676a2014-03-18 23:52:02203
dcheng04a35cd2016-04-22 15:07:24204 std::unique_ptr<DictionaryValue> report_value(new DictionaryValue());
[email protected]84d2a492014-05-09 22:18:50205 report_value->SetString("reporter", upload_reporter_string_);
jdoerriec1a515d2017-06-02 09:44:38206 report_value->Set("entries", std::move(beacons_value));
[email protected]45de676a2014-03-18 23:52:02207
ttuttle42144d8a2015-12-01 23:57:37208 *max_upload_depth_out = max_upload_depth;
dcheng51606352015-12-26 21:16:23209 return std::move(report_value);
[email protected]45de676a2014-03-18 23:52:02210}
211
212void DomainReliabilityContext::MarkUpload() {
[email protected]f3589bf2014-07-31 03:54:16213 DCHECK_EQ(0u, uploading_beacons_size_);
214 uploading_beacons_size_ = beacons_.size();
215 DCHECK_NE(0u, uploading_beacons_size_);
[email protected]45de676a2014-03-18 23:52:02216}
217
218void DomainReliabilityContext::CommitUpload() {
ttuttleccdd6cc52015-11-22 06:09:40219 auto begin = beacons_.begin();
220 auto end = begin + uploading_beacons_size_;
[email protected]f3589bf2014-07-31 03:54:16221 beacons_.erase(begin, end);
222 DCHECK_NE(0u, uploading_beacons_size_);
223 uploading_beacons_size_ = 0;
224}
225
226void DomainReliabilityContext::RollbackUpload() {
[email protected]f3589bf2014-07-31 03:54:16227 DCHECK_NE(0u, uploading_beacons_size_);
228 uploading_beacons_size_ = 0;
[email protected]45de676a2014-03-18 23:52:02229}
230
231void DomainReliabilityContext::RemoveOldestBeacon() {
[email protected]f3589bf2014-07-31 03:54:16232 DCHECK(!beacons_.empty());
[email protected]45de676a2014-03-18 23:52:02233
Misha Efimov99c53bcf2018-11-14 20:26:23234 DVLOG(1) << "Beacon queue for " << config().origin << " full; "
235 << "removing oldest beacon";
[email protected]45de676a2014-03-18 23:52:02236
[email protected]f3589bf2014-07-31 03:54:16237 beacons_.pop_front();
238
239 // If that just removed a beacon counted in uploading_beacons_size_, decrement
[email protected]45de676a2014-03-18 23:52:02240 // that.
[email protected]f3589bf2014-07-31 03:54:16241 if (uploading_beacons_size_ > 0)
242 --uploading_beacons_size_;
[email protected]45de676a2014-03-18 23:52:02243}
244
juliatuttle619e3562016-11-04 23:10:46245void DomainReliabilityContext::RemoveExpiredBeacons() {
246 base::TimeTicks now = time_->NowTicks();
247 const base::TimeDelta kMaxAge = base::TimeDelta::FromHours(1);
248 while (!beacons_.empty() && now - beacons_.front()->start_time >= kMaxAge)
249 beacons_.pop_front();
250}
251
[email protected]45de676a2014-03-18 23:52:02252} // namespace domain_reliability