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.
5 #include "components/domain_reliability/uploader.h"
8 #include "base/callback.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/metrics/sparse_histogram.h"
11 #include "base/stl_util.h"
12 #include "base/supports_user_data.h"
13 #include "net/base/load_flags.h"
14 #include "net/base/net_errors.h"
15 #include "net/url_request/url_fetcher.h"
16 #include "net/url_request/url_fetcher_delegate.h"
17 #include "net/url_request/url_request_context_getter.h"
19 namespace domain_reliability {
23 const char* kJsonMimeType = "application/json; charset=utf-8";
25 class UploadUserData : public base::SupportsUserData::Data {
27 static net::URLFetcher::CreateDataCallback CreateCreateDataCallback() {
28 return base::Bind(&UploadUserData::CreateUploadUserData);
31 static const void* kUserDataKey;
34 static base::SupportsUserData::Data* CreateUploadUserData() {
35 return new UploadUserData();
39 const void* UploadUserData::kUserDataKey =
40 static_cast<const void*>(&UploadUserData::kUserDataKey);
42 class DomainReliabilityUploaderImpl
43 : public DomainReliabilityUploader, net::URLFetcherDelegate {
45 DomainReliabilityUploaderImpl(const scoped_refptr<
46 net::URLRequestContextGetter>& url_request_context_getter)
47 : url_request_context_getter_(url_request_context_getter),
48 discard_uploads_(true) {}
50 ~DomainReliabilityUploaderImpl() override {
51 // Delete any in-flight URLFetchers.
52 STLDeleteContainerPairFirstPointers(
53 upload_callbacks_.begin(), upload_callbacks_.end());
56 // DomainReliabilityUploader implementation:
58 const std::string& report_json,
59 const GURL& upload_url,
60 const DomainReliabilityUploader::UploadCallback& callback) override {
61 VLOG(1) << "Uploading report to " << upload_url;
62 VLOG(2) << "Report JSON: " << report_json;
64 if (discard_uploads_) {
65 VLOG(1) << "Discarding report instead of uploading.";
70 net::URLFetcher* fetcher =
71 net::URLFetcher::Create(0, upload_url, net::URLFetcher::POST, this);
72 fetcher->SetRequestContext(url_request_context_getter_.get());
73 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
74 net::LOAD_DO_NOT_SAVE_COOKIES);
75 fetcher->SetUploadData(kJsonMimeType, report_json);
76 fetcher->SetAutomaticallyRetryOn5xx(false);
77 fetcher->SetURLRequestUserData(
78 UploadUserData::kUserDataKey,
79 UploadUserData::CreateCreateDataCallback());
82 upload_callbacks_[fetcher] = callback;
85 void set_discard_uploads(bool discard_uploads) override {
86 discard_uploads_ = discard_uploads;
87 VLOG(1) << "Setting discard_uploads to " << discard_uploads;
90 // net::URLFetcherDelegate implementation:
91 void OnURLFetchComplete(const net::URLFetcher* fetcher) override {
94 UploadCallbackMap::iterator callback_it = upload_callbacks_.find(fetcher);
95 DCHECK(callback_it != upload_callbacks_.end());
99 const net::URLRequestStatus& status = fetcher->GetStatus();
100 switch (status.status()) {
101 case net::URLRequestStatus::SUCCESS:
104 case net::URLRequestStatus::CANCELED:
105 net_error = net::ERR_ABORTED;
107 case net::URLRequestStatus::FAILED:
108 net_error = status.error();
112 net_error = net::ERR_FAILED;
116 int http_response_code = fetcher->GetResponseCode();
118 VLOG(1) << "Upload finished with net error " << net_error <<
119 " and HTTP response code " << http_response_code;
121 UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.UploadResponseCode",
123 UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.UploadNetError",
126 callback_it->second.Run(http_response_code == 200);
128 delete callback_it->first;
129 upload_callbacks_.erase(callback_it);
133 using DomainReliabilityUploader::UploadCallback;
134 typedef std::map<const net::URLFetcher*, UploadCallback> UploadCallbackMap;
136 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
137 UploadCallbackMap upload_callbacks_;
138 bool discard_uploads_;
143 DomainReliabilityUploader::DomainReliabilityUploader() {}
144 DomainReliabilityUploader::~DomainReliabilityUploader() {}
147 scoped_ptr<DomainReliabilityUploader> DomainReliabilityUploader::Create(
148 const scoped_refptr<net::URLRequestContextGetter>&
149 url_request_context_getter) {
150 return scoped_ptr<DomainReliabilityUploader>(
151 new DomainReliabilityUploaderImpl(url_request_context_getter));
155 bool DomainReliabilityUploader::URLRequestIsUpload(
156 const net::URLRequest& request) {
157 return request.GetUserData(UploadUserData::kUserDataKey) != NULL;
160 } // namespace domain_reliability