[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 1 | // 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/uploader.h" |
| 6 | |
avi | 12ce31d | 2016-08-30 16:38:05 | [diff] [blame] | 7 | #include <utility> |
| 8 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 9 | #include "base/bind.h" |
[email protected] | b5c2b74 | 2014-06-14 22:21:42 | [diff] [blame] | 10 | #include "base/callback.h" |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 11 | #include "base/logging.h" |
avi | 1ed4a437 | 2017-04-25 05:39:41 | [diff] [blame] | 12 | #include "base/memory/ptr_util.h" |
Ilya Sherman | 1edb6f18 | 2017-12-12 04:00:42 | [diff] [blame] | 13 | #include "base/metrics/histogram_functions.h" |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 14 | #include "base/supports_user_data.h" |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 15 | #include "components/domain_reliability/util.h" |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 16 | #include "net/base/load_flags.h" |
ttuttle | 128179a | 2014-10-31 23:25:19 | [diff] [blame] | 17 | #include "net/base/net_errors.h" |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 18 | #include "net/http/http_response_headers.h" |
| 19 | #include "net/http/http_util.h" |
rhalavati | 21ac0c1 | 2017-04-19 13:25:32 | [diff] [blame] | 20 | #include "net/traffic_annotation/network_traffic_annotation.h" |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 21 | #include "net/url_request/url_fetcher.h" |
| 22 | #include "net/url_request/url_fetcher_delegate.h" |
| 23 | #include "net/url_request/url_request_context_getter.h" |
| 24 | |
| 25 | namespace domain_reliability { |
| 26 | |
| 27 | namespace { |
| 28 | |
thestig | 3b6a2f1 | 2015-09-25 08:17:20 | [diff] [blame] | 29 | const char kJsonMimeType[] = "application/json; charset=utf-8"; |
[email protected] | 0d73f08 | 2014-05-07 22:30:23 | [diff] [blame] | 30 | |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 31 | class UploadUserData : public base::SupportsUserData::Data { |
| 32 | public: |
ttuttle | 42144d8a | 2015-12-01 23:57:37 | [diff] [blame] | 33 | static net::URLFetcher::CreateDataCallback CreateCreateDataCallback( |
| 34 | int depth) { |
| 35 | return base::Bind(&UploadUserData::CreateUploadUserData, depth); |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 36 | } |
| 37 | |
thestig | 3b6a2f1 | 2015-09-25 08:17:20 | [diff] [blame] | 38 | static const void* const kUserDataKey; |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 39 | |
ttuttle | 42144d8a | 2015-12-01 23:57:37 | [diff] [blame] | 40 | int depth() const { return depth_; } |
| 41 | |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 42 | private: |
ttuttle | 42144d8a | 2015-12-01 23:57:37 | [diff] [blame] | 43 | UploadUserData(int depth) : depth_(depth) {} |
| 44 | |
avi | 1ed4a437 | 2017-04-25 05:39:41 | [diff] [blame] | 45 | static std::unique_ptr<base::SupportsUserData::Data> CreateUploadUserData( |
| 46 | int depth) { |
| 47 | return base::WrapUnique(new UploadUserData(depth)); |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 48 | } |
ttuttle | 42144d8a | 2015-12-01 23:57:37 | [diff] [blame] | 49 | |
| 50 | int depth_; |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 51 | }; |
| 52 | |
thestig | 3b6a2f1 | 2015-09-25 08:17:20 | [diff] [blame] | 53 | const void* const UploadUserData::kUserDataKey = |
| 54 | &UploadUserData::kUserDataKey; |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 55 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 56 | class DomainReliabilityUploaderImpl |
| 57 | : public DomainReliabilityUploader, net::URLFetcherDelegate { |
| 58 | public: |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 59 | DomainReliabilityUploaderImpl( |
| 60 | MockableTime* time, |
Julia Tuttle | 30b16965 | 2017-10-16 20:19:08 | [diff] [blame] | 61 | const scoped_refptr<net::URLRequestContextGetter>& |
| 62 | url_request_context_getter) |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 63 | : time_(time), |
| 64 | url_request_context_getter_(url_request_context_getter), |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 65 | discard_uploads_(true), |
Julia Tuttle | 30b16965 | 2017-10-16 20:19:08 | [diff] [blame] | 66 | shutdown_(false), |
| 67 | discarded_upload_count_(0u) {} |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 68 | |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 69 | ~DomainReliabilityUploaderImpl() override { |
| 70 | DCHECK(shutdown_); |
| 71 | } |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 72 | |
| 73 | // DomainReliabilityUploader implementation: |
dcheng | 00ea022b | 2014-10-21 11:24:56 | [diff] [blame] | 74 | void UploadReport( |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 75 | const std::string& report_json, |
ttuttle | 42144d8a | 2015-12-01 23:57:37 | [diff] [blame] | 76 | int max_upload_depth, |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 77 | const GURL& upload_url, |
mostynb | fe59f48 | 2014-10-06 15:04:46 | [diff] [blame] | 78 | const DomainReliabilityUploader::UploadCallback& callback) override { |
Misha Efimov | 99c53bcf | 2018-11-14 20:26:23 | [diff] [blame] | 79 | DVLOG(1) << "Uploading report to " << upload_url; |
| 80 | DVLOG(2) << "Report JSON: " << report_json; |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 81 | |
Julia Tuttle | 30b16965 | 2017-10-16 20:19:08 | [diff] [blame] | 82 | if (discard_uploads_) |
| 83 | discarded_upload_count_++; |
| 84 | |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 85 | if (discard_uploads_ || shutdown_) { |
Misha Efimov | 99c53bcf | 2018-11-14 20:26:23 | [diff] [blame] | 86 | DVLOG(1) << "Discarding report instead of uploading."; |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 87 | UploadResult result; |
| 88 | result.status = UploadResult::SUCCESS; |
| 89 | callback.Run(result); |
ttuttle | fa8427f9 | 2014-08-25 19:38:03 | [diff] [blame] | 90 | return; |
| 91 | } |
| 92 | |
rhalavati | 21ac0c1 | 2017-04-19 13:25:32 | [diff] [blame] | 93 | net::NetworkTrafficAnnotationTag traffic_annotation = |
| 94 | net::DefineNetworkTrafficAnnotation("domain_reliability_report_upload", |
| 95 | R"( |
| 96 | semantics { |
| 97 | sender: "Domain Reliability" |
| 98 | description: |
| 99 | "If Chromium has trouble reaching certain Google sites or " |
| 100 | "services, Domain Reliability may report the problems back to " |
| 101 | "Google." |
| 102 | trigger: "Failure to load certain Google sites or services." |
| 103 | data: |
| 104 | "Details of the failed request, including the URL, any IP " |
| 105 | "addresses the browser tried to connect to, error(s) " |
| 106 | "encountered loading the resource, and other connection details." |
| 107 | destination: GOOGLE_OWNED_SERVICE |
| 108 | } |
| 109 | policy { |
Ramin Halavati | 3b97978 | 2017-07-21 11:40:26 | [diff] [blame] | 110 | cookies_allowed: NO |
rhalavati | 21ac0c1 | 2017-04-19 13:25:32 | [diff] [blame] | 111 | setting: |
| 112 | "Users can enable or disable Domain Reliability on desktop, via " |
| 113 | "toggling 'Automatically send usage statistics and crash reports " |
| 114 | "to Google' in Chromium's settings under Privacy. On ChromeOS, " |
| 115 | "the setting is named 'Automatically send diagnostic and usage " |
| 116 | "data to Google'." |
| 117 | policy_exception_justification: "Not implemented." |
| 118 | })"); |
| 119 | std::unique_ptr<net::URLFetcher> owned_fetcher = net::URLFetcher::Create( |
| 120 | 0, upload_url, net::URLFetcher::POST, this, traffic_annotation); |
avi | 12ce31d | 2016-08-30 16:38:05 | [diff] [blame] | 121 | net::URLFetcher* fetcher = owned_fetcher.get(); |
dcheng | 45252e8e | 2014-08-26 17:59:54 | [diff] [blame] | 122 | fetcher->SetRequestContext(url_request_context_getter_.get()); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 123 | fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 124 | net::LOAD_DO_NOT_SAVE_COOKIES); |
[email protected] | 0d73f08 | 2014-05-07 22:30:23 | [diff] [blame] | 125 | fetcher->SetUploadData(kJsonMimeType, report_json); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 126 | fetcher->SetAutomaticallyRetryOn5xx(false); |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 127 | fetcher->SetURLRequestUserData( |
| 128 | UploadUserData::kUserDataKey, |
ttuttle | 42144d8a | 2015-12-01 23:57:37 | [diff] [blame] | 129 | UploadUserData::CreateCreateDataCallback(max_upload_depth + 1)); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 130 | fetcher->Start(); |
| 131 | |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 132 | uploads_[fetcher] = {std::move(owned_fetcher), callback}; |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 133 | } |
| 134 | |
Julia Tuttle | 30b16965 | 2017-10-16 20:19:08 | [diff] [blame] | 135 | void SetDiscardUploads(bool discard_uploads) override { |
ttuttle | fa8427f9 | 2014-08-25 19:38:03 | [diff] [blame] | 136 | discard_uploads_ = discard_uploads; |
Misha Efimov | 99c53bcf | 2018-11-14 20:26:23 | [diff] [blame] | 137 | DVLOG(1) << "Setting discard_uploads to " << discard_uploads; |
ttuttle | fa8427f9 | 2014-08-25 19:38:03 | [diff] [blame] | 138 | } |
| 139 | |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 140 | void Shutdown() override { |
| 141 | DCHECK(!shutdown_); |
| 142 | shutdown_ = true; |
| 143 | uploads_.clear(); |
| 144 | } |
| 145 | |
Julia Tuttle | 30b16965 | 2017-10-16 20:19:08 | [diff] [blame] | 146 | int GetDiscardedUploadCount() const override { |
| 147 | return discarded_upload_count_; |
| 148 | } |
| 149 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 150 | // net::URLFetcherDelegate implementation: |
dcheng | 00ea022b | 2014-10-21 11:24:56 | [diff] [blame] | 151 | void OnURLFetchComplete(const net::URLFetcher* fetcher) override { |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 152 | DCHECK(fetcher); |
| 153 | |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 154 | auto callback_it = uploads_.find(fetcher); |
| 155 | DCHECK(callback_it != uploads_.end()); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 156 | |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 157 | int net_error = GetNetErrorFromURLRequestStatus(fetcher->GetStatus()); |
| 158 | int http_response_code = fetcher->GetResponseCode(); |
| 159 | base::TimeDelta retry_after; |
ttuttle | 128179a | 2014-10-31 23:25:19 | [diff] [blame] | 160 | { |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 161 | std::string retry_after_string; |
ttuttle | d42b1463 | 2014-11-19 00:40:29 | [diff] [blame] | 162 | if (fetcher->GetResponseHeaders() && |
ttuttle | c72f27d | 2015-03-17 23:55:59 | [diff] [blame] | 163 | fetcher->GetResponseHeaders()->EnumerateHeader(nullptr, |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 164 | "Retry-After", |
| 165 | &retry_after_string)) { |
| 166 | net::HttpUtil::ParseRetryAfterHeader(retry_after_string, |
| 167 | time_->Now(), |
| 168 | &retry_after); |
ttuttle | 128179a | 2014-10-31 23:25:19 | [diff] [blame] | 169 | } |
| 170 | } |
ttuttle | 128179a | 2014-10-31 23:25:19 | [diff] [blame] | 171 | |
Misha Efimov | 99c53bcf | 2018-11-14 20:26:23 | [diff] [blame] | 172 | DVLOG(1) << "Upload finished with net error " << net_error |
| 173 | << ", response code " << http_response_code << ", retry after " |
| 174 | << retry_after; |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 175 | |
Ilya Sherman | 1edb6f18 | 2017-12-12 04:00:42 | [diff] [blame] | 176 | base::UmaHistogramSparse("DomainReliability.UploadResponseCode", |
| 177 | http_response_code); |
| 178 | base::UmaHistogramSparse("DomainReliability.UploadNetError", -net_error); |
[email protected] | d9df3b8 | 2014-04-08 23:44:00 | [diff] [blame] | 179 | |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 180 | UploadResult result; |
| 181 | GetUploadResultFromResponseDetails(net_error, |
| 182 | http_response_code, |
| 183 | retry_after, |
| 184 | &result); |
avi | 12ce31d | 2016-08-30 16:38:05 | [diff] [blame] | 185 | callback_it->second.second.Run(result); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 186 | |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 187 | uploads_.erase(callback_it); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 188 | } |
| 189 | |
| 190 | private: |
| 191 | using DomainReliabilityUploader::UploadCallback; |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 192 | |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 193 | MockableTime* time_; |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 194 | scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; |
avi | 12ce31d | 2016-08-30 16:38:05 | [diff] [blame] | 195 | std::map<const net::URLFetcher*, |
| 196 | std::pair<std::unique_ptr<net::URLFetcher>, UploadCallback>> |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 197 | uploads_; |
ttuttle | fa8427f9 | 2014-08-25 19:38:03 | [diff] [blame] | 198 | bool discard_uploads_; |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 199 | bool shutdown_; |
Julia Tuttle | 30b16965 | 2017-10-16 20:19:08 | [diff] [blame] | 200 | int discarded_upload_count_; |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 201 | }; |
| 202 | |
| 203 | } // namespace |
| 204 | |
| 205 | DomainReliabilityUploader::DomainReliabilityUploader() {} |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 206 | DomainReliabilityUploader::~DomainReliabilityUploader() {} |
| 207 | |
| 208 | // static |
mostynb | ea64f7c | 2016-04-03 16:03:44 | [diff] [blame] | 209 | std::unique_ptr<DomainReliabilityUploader> DomainReliabilityUploader::Create( |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 210 | MockableTime* time, |
[email protected] | 84d2a49 | 2014-05-09 22:18:50 | [diff] [blame] | 211 | const scoped_refptr<net::URLRequestContextGetter>& |
| 212 | url_request_context_getter) { |
mostynb | ea64f7c | 2016-04-03 16:03:44 | [diff] [blame] | 213 | return std::unique_ptr<DomainReliabilityUploader>( |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 214 | new DomainReliabilityUploaderImpl(time, url_request_context_getter)); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 215 | } |
| 216 | |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 217 | // static |
ttuttle | 42144d8a | 2015-12-01 23:57:37 | [diff] [blame] | 218 | int DomainReliabilityUploader::GetURLRequestUploadDepth( |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 219 | const net::URLRequest& request) { |
ttuttle | 42144d8a | 2015-12-01 23:57:37 | [diff] [blame] | 220 | UploadUserData* data = static_cast<UploadUserData*>( |
| 221 | request.GetUserData(UploadUserData::kUserDataKey)); |
| 222 | if (!data) |
| 223 | return 0; |
| 224 | return data->depth(); |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 225 | } |
| 226 | |
juliatuttle | 127604ea | 2016-12-19 19:13:04 | [diff] [blame] | 227 | void DomainReliabilityUploader::Shutdown() {} |
| 228 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 229 | } // namespace domain_reliability |