123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/domain_reliability/uploader.h"
- #include <utility>
- #include "base/callback.h"
- #include "base/containers/unique_ptr_adapters.h"
- #include "base/logging.h"
- #include "base/memory/raw_ptr.h"
- #include "base/supports_user_data.h"
- #include "components/domain_reliability/util.h"
- #include "net/base/elements_upload_data_stream.h"
- #include "net/base/isolation_info.h"
- #include "net/base/net_errors.h"
- #include "net/base/upload_bytes_element_reader.h"
- #include "net/http/http_response_headers.h"
- #include "net/http/http_util.h"
- #include "net/traffic_annotation/network_traffic_annotation.h"
- #include "net/url_request/url_request.h"
- #include "net/url_request/url_request_context.h"
- namespace domain_reliability {
- namespace {
- const char kJsonMimeType[] = "application/json; charset=utf-8";
- // Each DR upload is tagged with an instance of this class, which identifies the
- // depth of the upload. This is to prevent infinite loops of DR uploads about DR
- // uploads, leading to an unbounded number of requests.
- // Deeper requests will still generate a report beacon, but they won't trigger a
- // separate upload. See DomainReliabilityContext::kMaxUploadDepthToSchedule.
- struct UploadDepthData : public base::SupportsUserData::Data {
- explicit UploadDepthData(int depth) : depth(depth) {}
- // Key that identifies this data within SupportsUserData's map of data.
- static const void* const kUserDataKey;
- // This is 0 if the report being uploaded does not contain a beacon about a
- // DR upload request. Otherwise, it is 1 + the depth of the deepest DR upload
- // described in the report.
- int depth;
- };
- const void* const UploadDepthData::kUserDataKey =
- &UploadDepthData::kUserDataKey;
- } // namespace
- class DomainReliabilityUploaderImpl : public DomainReliabilityUploader,
- public net::URLRequest::Delegate {
- public:
- DomainReliabilityUploaderImpl(MockableTime* time,
- net::URLRequestContext* url_request_context)
- : time_(time),
- url_request_context_(url_request_context),
- discard_uploads_(true),
- shutdown_(false),
- discarded_upload_count_(0u) {
- DCHECK(url_request_context_);
- }
- ~DomainReliabilityUploaderImpl() override {
- DCHECK(shutdown_);
- }
- // DomainReliabilityUploader implementation:
- void UploadReport(
- const std::string& report_json,
- int max_upload_depth,
- const GURL& upload_url,
- const net::NetworkIsolationKey& network_isolation_key,
- DomainReliabilityUploader::UploadCallback callback) override {
- DVLOG(1) << "Uploading report to " << upload_url;
- DVLOG(2) << "Report JSON: " << report_json;
- if (discard_uploads_)
- discarded_upload_count_++;
- if (discard_uploads_ || shutdown_) {
- DVLOG(1) << "Discarding report instead of uploading.";
- UploadResult result;
- result.status = UploadResult::SUCCESS;
- std::move(callback).Run(result);
- return;
- }
- net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation("domain_reliability_report_upload",
- R"(
- semantics {
- sender: "Domain Reliability"
- description:
- "If Chromium has trouble reaching certain Google sites or "
- "services, Domain Reliability may report the problems back to "
- "Google."
- trigger: "Failure to load certain Google sites or services."
- data:
- "Details of the failed request, including the URL, any IP "
- "addresses the browser tried to connect to, error(s) "
- "encountered loading the resource, and other connection details."
- destination: GOOGLE_OWNED_SERVICE
- }
- policy {
- cookies_allowed: NO
- setting:
- "Users can enable or disable Domain Reliability on desktop, via "
- "toggling 'Automatically send usage statistics and crash reports "
- "to Google' in Chromium's settings under Privacy. On ChromeOS, "
- "the setting is named 'Automatically send diagnostic and usage "
- "data to Google'."
- policy_exception_justification: "Not implemented."
- })");
- std::unique_ptr<net::URLRequest> request =
- url_request_context_->CreateRequest(
- upload_url, net::RequestPriority::IDLE, this /* delegate */,
- traffic_annotation);
- request->set_method("POST");
- request->set_allow_credentials(false);
- request->SetExtraRequestHeaderByName(net::HttpRequestHeaders::kContentType,
- kJsonMimeType, true /* overwrite */);
- request->set_isolation_info(net::IsolationInfo::CreatePartial(
- net::IsolationInfo::RequestType::kOther, network_isolation_key));
- std::vector<char> report_data(report_json.begin(), report_json.end());
- auto upload_reader =
- std::make_unique<net::UploadOwnedBytesElementReader>(&report_data);
- request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
- std::move(upload_reader), 0 /* identifier */));
- request->SetUserData(
- UploadDepthData::kUserDataKey,
- std::make_unique<UploadDepthData>(max_upload_depth + 1));
- auto [it, inserted] = uploads_.insert(
- std::make_pair(std::move(request), std::move(callback)));
- DCHECK(inserted);
- it->first->Start();
- }
- void SetDiscardUploads(bool discard_uploads) override {
- discard_uploads_ = discard_uploads;
- DVLOG(1) << "Setting discard_uploads to " << discard_uploads;
- }
- void Shutdown() override {
- DCHECK(!shutdown_);
- shutdown_ = true;
- uploads_.clear();
- }
- int GetDiscardedUploadCount() const override {
- return discarded_upload_count_;
- }
- // net::URLRequest::Delegate implementation:
- void OnResponseStarted(net::URLRequest* request, int net_error) override {
- DCHECK(!shutdown_);
- auto request_it = uploads_.find(request);
- DCHECK(request_it != uploads_.end());
- int http_response_code = -1;
- base::TimeDelta retry_after;
- if (net_error == net::OK) {
- http_response_code = request->GetResponseCode();
- std::string retry_after_string;
- if (request->response_headers() &&
- request->response_headers()->EnumerateHeader(nullptr, "Retry-After",
- &retry_after_string)) {
- net::HttpUtil::ParseRetryAfterHeader(retry_after_string, time_->Now(),
- &retry_after);
- }
- }
- DVLOG(1) << "Upload finished with net error " << net_error
- << ", response code " << http_response_code << ", retry after "
- << retry_after;
- std::move(request_it->second)
- .Run(GetUploadResultFromResponseDetails(net_error, http_response_code,
- retry_after));
- uploads_.erase(request_it);
- }
- // Requests are cancelled in OnResponseStarted() once response headers are
- // read, without reading the body, so this is not needed.
- void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
- NOTREACHED();
- }
- private:
- raw_ptr<MockableTime> time_;
- raw_ptr<net::URLRequestContext> url_request_context_;
- // Stores each in-flight upload request with the callback to notify its
- // initiating DRContext of its completion.
- using UploadMap = std::map<std::unique_ptr<net::URLRequest>,
- UploadCallback,
- base::UniquePtrComparator>;
- UploadMap uploads_;
- bool discard_uploads_;
- bool shutdown_;
- int discarded_upload_count_;
- };
- DomainReliabilityUploader::DomainReliabilityUploader() {}
- DomainReliabilityUploader::~DomainReliabilityUploader() {}
- // static
- std::unique_ptr<DomainReliabilityUploader> DomainReliabilityUploader::Create(
- MockableTime* time,
- net::URLRequestContext* url_request_context) {
- return std::make_unique<DomainReliabilityUploaderImpl>(time,
- url_request_context);
- }
- // static
- int DomainReliabilityUploader::GetURLRequestUploadDepth(
- const net::URLRequest& request) {
- UploadDepthData* data = static_cast<UploadDepthData*>(
- request.GetUserData(UploadDepthData::kUserDataKey));
- return data ? data->depth : 0;
- }
- } // namespace domain_reliability
|