uploader.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. #include "components/domain_reliability/uploader.h"
  5. #include <utility>
  6. #include "base/callback.h"
  7. #include "base/containers/unique_ptr_adapters.h"
  8. #include "base/logging.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/supports_user_data.h"
  11. #include "components/domain_reliability/util.h"
  12. #include "net/base/elements_upload_data_stream.h"
  13. #include "net/base/isolation_info.h"
  14. #include "net/base/net_errors.h"
  15. #include "net/base/upload_bytes_element_reader.h"
  16. #include "net/http/http_response_headers.h"
  17. #include "net/http/http_util.h"
  18. #include "net/traffic_annotation/network_traffic_annotation.h"
  19. #include "net/url_request/url_request.h"
  20. #include "net/url_request/url_request_context.h"
  21. namespace domain_reliability {
  22. namespace {
  23. const char kJsonMimeType[] = "application/json; charset=utf-8";
  24. // Each DR upload is tagged with an instance of this class, which identifies the
  25. // depth of the upload. This is to prevent infinite loops of DR uploads about DR
  26. // uploads, leading to an unbounded number of requests.
  27. // Deeper requests will still generate a report beacon, but they won't trigger a
  28. // separate upload. See DomainReliabilityContext::kMaxUploadDepthToSchedule.
  29. struct UploadDepthData : public base::SupportsUserData::Data {
  30. explicit UploadDepthData(int depth) : depth(depth) {}
  31. // Key that identifies this data within SupportsUserData's map of data.
  32. static const void* const kUserDataKey;
  33. // This is 0 if the report being uploaded does not contain a beacon about a
  34. // DR upload request. Otherwise, it is 1 + the depth of the deepest DR upload
  35. // described in the report.
  36. int depth;
  37. };
  38. const void* const UploadDepthData::kUserDataKey =
  39. &UploadDepthData::kUserDataKey;
  40. } // namespace
  41. class DomainReliabilityUploaderImpl : public DomainReliabilityUploader,
  42. public net::URLRequest::Delegate {
  43. public:
  44. DomainReliabilityUploaderImpl(MockableTime* time,
  45. net::URLRequestContext* url_request_context)
  46. : time_(time),
  47. url_request_context_(url_request_context),
  48. discard_uploads_(true),
  49. shutdown_(false),
  50. discarded_upload_count_(0u) {
  51. DCHECK(url_request_context_);
  52. }
  53. ~DomainReliabilityUploaderImpl() override {
  54. DCHECK(shutdown_);
  55. }
  56. // DomainReliabilityUploader implementation:
  57. void UploadReport(
  58. const std::string& report_json,
  59. int max_upload_depth,
  60. const GURL& upload_url,
  61. const net::NetworkIsolationKey& network_isolation_key,
  62. DomainReliabilityUploader::UploadCallback callback) override {
  63. DVLOG(1) << "Uploading report to " << upload_url;
  64. DVLOG(2) << "Report JSON: " << report_json;
  65. if (discard_uploads_)
  66. discarded_upload_count_++;
  67. if (discard_uploads_ || shutdown_) {
  68. DVLOG(1) << "Discarding report instead of uploading.";
  69. UploadResult result;
  70. result.status = UploadResult::SUCCESS;
  71. std::move(callback).Run(result);
  72. return;
  73. }
  74. net::NetworkTrafficAnnotationTag traffic_annotation =
  75. net::DefineNetworkTrafficAnnotation("domain_reliability_report_upload",
  76. R"(
  77. semantics {
  78. sender: "Domain Reliability"
  79. description:
  80. "If Chromium has trouble reaching certain Google sites or "
  81. "services, Domain Reliability may report the problems back to "
  82. "Google."
  83. trigger: "Failure to load certain Google sites or services."
  84. data:
  85. "Details of the failed request, including the URL, any IP "
  86. "addresses the browser tried to connect to, error(s) "
  87. "encountered loading the resource, and other connection details."
  88. destination: GOOGLE_OWNED_SERVICE
  89. }
  90. policy {
  91. cookies_allowed: NO
  92. setting:
  93. "Users can enable or disable Domain Reliability on desktop, via "
  94. "toggling 'Automatically send usage statistics and crash reports "
  95. "to Google' in Chromium's settings under Privacy. On ChromeOS, "
  96. "the setting is named 'Automatically send diagnostic and usage "
  97. "data to Google'."
  98. policy_exception_justification: "Not implemented."
  99. })");
  100. std::unique_ptr<net::URLRequest> request =
  101. url_request_context_->CreateRequest(
  102. upload_url, net::RequestPriority::IDLE, this /* delegate */,
  103. traffic_annotation);
  104. request->set_method("POST");
  105. request->set_allow_credentials(false);
  106. request->SetExtraRequestHeaderByName(net::HttpRequestHeaders::kContentType,
  107. kJsonMimeType, true /* overwrite */);
  108. request->set_isolation_info(net::IsolationInfo::CreatePartial(
  109. net::IsolationInfo::RequestType::kOther, network_isolation_key));
  110. std::vector<char> report_data(report_json.begin(), report_json.end());
  111. auto upload_reader =
  112. std::make_unique<net::UploadOwnedBytesElementReader>(&report_data);
  113. request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
  114. std::move(upload_reader), 0 /* identifier */));
  115. request->SetUserData(
  116. UploadDepthData::kUserDataKey,
  117. std::make_unique<UploadDepthData>(max_upload_depth + 1));
  118. auto [it, inserted] = uploads_.insert(
  119. std::make_pair(std::move(request), std::move(callback)));
  120. DCHECK(inserted);
  121. it->first->Start();
  122. }
  123. void SetDiscardUploads(bool discard_uploads) override {
  124. discard_uploads_ = discard_uploads;
  125. DVLOG(1) << "Setting discard_uploads to " << discard_uploads;
  126. }
  127. void Shutdown() override {
  128. DCHECK(!shutdown_);
  129. shutdown_ = true;
  130. uploads_.clear();
  131. }
  132. int GetDiscardedUploadCount() const override {
  133. return discarded_upload_count_;
  134. }
  135. // net::URLRequest::Delegate implementation:
  136. void OnResponseStarted(net::URLRequest* request, int net_error) override {
  137. DCHECK(!shutdown_);
  138. auto request_it = uploads_.find(request);
  139. DCHECK(request_it != uploads_.end());
  140. int http_response_code = -1;
  141. base::TimeDelta retry_after;
  142. if (net_error == net::OK) {
  143. http_response_code = request->GetResponseCode();
  144. std::string retry_after_string;
  145. if (request->response_headers() &&
  146. request->response_headers()->EnumerateHeader(nullptr, "Retry-After",
  147. &retry_after_string)) {
  148. net::HttpUtil::ParseRetryAfterHeader(retry_after_string, time_->Now(),
  149. &retry_after);
  150. }
  151. }
  152. DVLOG(1) << "Upload finished with net error " << net_error
  153. << ", response code " << http_response_code << ", retry after "
  154. << retry_after;
  155. std::move(request_it->second)
  156. .Run(GetUploadResultFromResponseDetails(net_error, http_response_code,
  157. retry_after));
  158. uploads_.erase(request_it);
  159. }
  160. // Requests are cancelled in OnResponseStarted() once response headers are
  161. // read, without reading the body, so this is not needed.
  162. void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
  163. NOTREACHED();
  164. }
  165. private:
  166. raw_ptr<MockableTime> time_;
  167. raw_ptr<net::URLRequestContext> url_request_context_;
  168. // Stores each in-flight upload request with the callback to notify its
  169. // initiating DRContext of its completion.
  170. using UploadMap = std::map<std::unique_ptr<net::URLRequest>,
  171. UploadCallback,
  172. base::UniquePtrComparator>;
  173. UploadMap uploads_;
  174. bool discard_uploads_;
  175. bool shutdown_;
  176. int discarded_upload_count_;
  177. };
  178. DomainReliabilityUploader::DomainReliabilityUploader() {}
  179. DomainReliabilityUploader::~DomainReliabilityUploader() {}
  180. // static
  181. std::unique_ptr<DomainReliabilityUploader> DomainReliabilityUploader::Create(
  182. MockableTime* time,
  183. net::URLRequestContext* url_request_context) {
  184. return std::make_unique<DomainReliabilityUploaderImpl>(time,
  185. url_request_context);
  186. }
  187. // static
  188. int DomainReliabilityUploader::GetURLRequestUploadDepth(
  189. const net::URLRequest& request) {
  190. UploadDepthData* data = static_cast<UploadDepthData*>(
  191. request.GetUserData(UploadDepthData::kUserDataKey));
  192. return data ? data->depth : 0;
  193. }
  194. } // namespace domain_reliability