[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 | |
| 7 | #include "base/bind.h" |
[email protected] | b5c2b74 | 2014-06-14 22:21:42 | [diff] [blame] | 8 | #include "base/callback.h" |
[email protected] | d9df3b8 | 2014-04-08 23:44:00 | [diff] [blame] | 9 | #include "base/metrics/sparse_histogram.h" |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 10 | #include "base/stl_util.h" |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 11 | #include "base/supports_user_data.h" |
amohammadkhan | f76ae11 | 2015-09-14 17:34:43 | [diff] [blame] | 12 | #include "components/data_use_measurement/core/data_use_user_data.h" |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 13 | #include "components/domain_reliability/util.h" |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 14 | #include "net/base/load_flags.h" |
ttuttle | 128179a | 2014-10-31 23:25:19 | [diff] [blame] | 15 | #include "net/base/net_errors.h" |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 16 | #include "net/http/http_response_headers.h" |
| 17 | #include "net/http/http_util.h" |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 18 | #include "net/url_request/url_fetcher.h" |
| 19 | #include "net/url_request/url_fetcher_delegate.h" |
| 20 | #include "net/url_request/url_request_context_getter.h" |
| 21 | |
| 22 | namespace domain_reliability { |
| 23 | |
| 24 | namespace { |
| 25 | |
thestig | 3b6a2f1 | 2015-09-25 08:17:20 | [diff] [blame^] | 26 | const char kJsonMimeType[] = "application/json; charset=utf-8"; |
[email protected] | 0d73f08 | 2014-05-07 22:30:23 | [diff] [blame] | 27 | |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 28 | class UploadUserData : public base::SupportsUserData::Data { |
| 29 | public: |
| 30 | static net::URLFetcher::CreateDataCallback CreateCreateDataCallback() { |
| 31 | return base::Bind(&UploadUserData::CreateUploadUserData); |
| 32 | } |
| 33 | |
thestig | 3b6a2f1 | 2015-09-25 08:17:20 | [diff] [blame^] | 34 | static const void* const kUserDataKey; |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 35 | |
| 36 | private: |
| 37 | static base::SupportsUserData::Data* CreateUploadUserData() { |
| 38 | return new UploadUserData(); |
| 39 | } |
| 40 | }; |
| 41 | |
thestig | 3b6a2f1 | 2015-09-25 08:17:20 | [diff] [blame^] | 42 | const void* const UploadUserData::kUserDataKey = |
| 43 | &UploadUserData::kUserDataKey; |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 44 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 45 | class DomainReliabilityUploaderImpl |
| 46 | : public DomainReliabilityUploader, net::URLFetcherDelegate { |
| 47 | public: |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 48 | DomainReliabilityUploaderImpl( |
| 49 | MockableTime* time, |
| 50 | const scoped_refptr< |
| 51 | net::URLRequestContextGetter>& url_request_context_getter) |
| 52 | : time_(time), |
| 53 | url_request_context_getter_(url_request_context_getter), |
ttuttle | fa8427f9 | 2014-08-25 19:38:03 | [diff] [blame] | 54 | discard_uploads_(true) {} |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 55 | |
dcheng | 00ea022b | 2014-10-21 11:24:56 | [diff] [blame] | 56 | ~DomainReliabilityUploaderImpl() override { |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 57 | // Delete any in-flight URLFetchers. |
| 58 | STLDeleteContainerPairFirstPointers( |
| 59 | upload_callbacks_.begin(), upload_callbacks_.end()); |
| 60 | } |
| 61 | |
| 62 | // DomainReliabilityUploader implementation: |
dcheng | 00ea022b | 2014-10-21 11:24:56 | [diff] [blame] | 63 | void UploadReport( |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 64 | const std::string& report_json, |
| 65 | const GURL& upload_url, |
mostynb | fe59f48 | 2014-10-06 15:04:46 | [diff] [blame] | 66 | const DomainReliabilityUploader::UploadCallback& callback) override { |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 67 | VLOG(1) << "Uploading report to " << upload_url; |
| 68 | VLOG(2) << "Report JSON: " << report_json; |
| 69 | |
ttuttle | fa8427f9 | 2014-08-25 19:38:03 | [diff] [blame] | 70 | if (discard_uploads_) { |
| 71 | VLOG(1) << "Discarding report instead of uploading."; |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 72 | UploadResult result; |
| 73 | result.status = UploadResult::SUCCESS; |
| 74 | callback.Run(result); |
ttuttle | fa8427f9 | 2014-08-25 19:38:03 | [diff] [blame] | 75 | return; |
| 76 | } |
| 77 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 78 | net::URLFetcher* fetcher = |
dtapuska | dafcf89 | 2015-05-01 13:58:25 | [diff] [blame] | 79 | net::URLFetcher::Create(0, upload_url, net::URLFetcher::POST, this) |
| 80 | .release(); |
amohammadkhan | f76ae11 | 2015-09-14 17:34:43 | [diff] [blame] | 81 | data_use_measurement::DataUseUserData::AttachToFetcher( |
| 82 | fetcher, data_use_measurement::DataUseUserData::DOMAIN_RELIABILITY); |
dcheng | 45252e8e | 2014-08-26 17:59:54 | [diff] [blame] | 83 | fetcher->SetRequestContext(url_request_context_getter_.get()); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 84 | fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 85 | net::LOAD_DO_NOT_SAVE_COOKIES); |
[email protected] | 0d73f08 | 2014-05-07 22:30:23 | [diff] [blame] | 86 | fetcher->SetUploadData(kJsonMimeType, report_json); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 87 | fetcher->SetAutomaticallyRetryOn5xx(false); |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 88 | fetcher->SetURLRequestUserData( |
| 89 | UploadUserData::kUserDataKey, |
| 90 | UploadUserData::CreateCreateDataCallback()); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 91 | fetcher->Start(); |
| 92 | |
| 93 | upload_callbacks_[fetcher] = callback; |
| 94 | } |
| 95 | |
dcheng | 00ea022b | 2014-10-21 11:24:56 | [diff] [blame] | 96 | void set_discard_uploads(bool discard_uploads) override { |
ttuttle | fa8427f9 | 2014-08-25 19:38:03 | [diff] [blame] | 97 | discard_uploads_ = discard_uploads; |
| 98 | VLOG(1) << "Setting discard_uploads to " << discard_uploads; |
| 99 | } |
| 100 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 101 | // net::URLFetcherDelegate implementation: |
dcheng | 00ea022b | 2014-10-21 11:24:56 | [diff] [blame] | 102 | void OnURLFetchComplete(const net::URLFetcher* fetcher) override { |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 103 | DCHECK(fetcher); |
| 104 | |
| 105 | UploadCallbackMap::iterator callback_it = upload_callbacks_.find(fetcher); |
| 106 | DCHECK(callback_it != upload_callbacks_.end()); |
| 107 | |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 108 | int net_error = GetNetErrorFromURLRequestStatus(fetcher->GetStatus()); |
| 109 | int http_response_code = fetcher->GetResponseCode(); |
| 110 | base::TimeDelta retry_after; |
ttuttle | 128179a | 2014-10-31 23:25:19 | [diff] [blame] | 111 | { |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 112 | std::string retry_after_string; |
ttuttle | d42b1463 | 2014-11-19 00:40:29 | [diff] [blame] | 113 | if (fetcher->GetResponseHeaders() && |
ttuttle | c72f27d | 2015-03-17 23:55:59 | [diff] [blame] | 114 | fetcher->GetResponseHeaders()->EnumerateHeader(nullptr, |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 115 | "Retry-After", |
| 116 | &retry_after_string)) { |
| 117 | net::HttpUtil::ParseRetryAfterHeader(retry_after_string, |
| 118 | time_->Now(), |
| 119 | &retry_after); |
ttuttle | 128179a | 2014-10-31 23:25:19 | [diff] [blame] | 120 | } |
| 121 | } |
ttuttle | 128179a | 2014-10-31 23:25:19 | [diff] [blame] | 122 | |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 123 | VLOG(1) << "Upload finished with net error " << net_error |
| 124 | << ", response code " << http_response_code |
| 125 | << ", retry after " << retry_after; |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 126 | |
[email protected] | d9df3b8 | 2014-04-08 23:44:00 | [diff] [blame] | 127 | UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.UploadResponseCode", |
ttuttle | 128179a | 2014-10-31 23:25:19 | [diff] [blame] | 128 | http_response_code); |
| 129 | UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.UploadNetError", |
| 130 | -net_error); |
[email protected] | d9df3b8 | 2014-04-08 23:44:00 | [diff] [blame] | 131 | |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 132 | UploadResult result; |
| 133 | GetUploadResultFromResponseDetails(net_error, |
| 134 | http_response_code, |
| 135 | retry_after, |
| 136 | &result); |
| 137 | callback_it->second.Run(result); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 138 | |
| 139 | delete callback_it->first; |
| 140 | upload_callbacks_.erase(callback_it); |
| 141 | } |
| 142 | |
| 143 | private: |
| 144 | using DomainReliabilityUploader::UploadCallback; |
| 145 | typedef std::map<const net::URLFetcher*, UploadCallback> UploadCallbackMap; |
| 146 | |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 147 | MockableTime* time_; |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 148 | scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; |
| 149 | UploadCallbackMap upload_callbacks_; |
ttuttle | fa8427f9 | 2014-08-25 19:38:03 | [diff] [blame] | 150 | bool discard_uploads_; |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 151 | }; |
| 152 | |
| 153 | } // namespace |
| 154 | |
| 155 | DomainReliabilityUploader::DomainReliabilityUploader() {} |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 156 | DomainReliabilityUploader::~DomainReliabilityUploader() {} |
| 157 | |
| 158 | // static |
| 159 | scoped_ptr<DomainReliabilityUploader> DomainReliabilityUploader::Create( |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 160 | MockableTime* time, |
[email protected] | 84d2a49 | 2014-05-09 22:18:50 | [diff] [blame] | 161 | const scoped_refptr<net::URLRequestContextGetter>& |
| 162 | url_request_context_getter) { |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 163 | return scoped_ptr<DomainReliabilityUploader>( |
ttuttle | 280a73d | 2014-11-13 21:38:04 | [diff] [blame] | 164 | new DomainReliabilityUploaderImpl(time, url_request_context_getter)); |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 165 | } |
| 166 | |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 167 | // static |
| 168 | bool DomainReliabilityUploader::URLRequestIsUpload( |
| 169 | const net::URLRequest& request) { |
ttuttle | c72f27d | 2015-03-17 23:55:59 | [diff] [blame] | 170 | return request.GetUserData(UploadUserData::kUserDataKey) != nullptr; |
[email protected] | d1acfe0 | 2014-04-24 17:15:29 | [diff] [blame] | 171 | } |
| 172 | |
[email protected] | bda8e36 | 2014-03-24 18:21:03 | [diff] [blame] | 173 | } // namespace domain_reliability |