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" 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/url_request/url_fetcher.h" 15 #include "net/url_request/url_fetcher_delegate.h" 16 #include "net/url_request/url_request_context_getter.h" 17 18 namespace domain_reliability { 19 20 namespace { 21 22 const char* kJsonMimeType = "application/json; charset=utf-8"; 23 24 class UploadUserData : public base::SupportsUserData::Data { 25 public: 26 static net::URLFetcher::CreateDataCallback CreateCreateDataCallback() { 27 return base::Bind(&UploadUserData::CreateUploadUserData); 28 } 29 30 static const void* kUserDataKey; 31 32 private: 33 static base::SupportsUserData::Data* CreateUploadUserData() { 34 return new UploadUserData(); 35 } 36 }; 37 38 const void* UploadUserData::kUserDataKey = 39 static_cast<const void*>(&UploadUserData::kUserDataKey); 40 41 class DomainReliabilityUploaderImpl 42 : public DomainReliabilityUploader, net::URLFetcherDelegate { 43 public: 44 DomainReliabilityUploaderImpl(const scoped_refptr< 45 net::URLRequestContextGetter>& url_request_context_getter) 46 : url_request_context_getter_(url_request_context_getter), 47 discard_uploads_(true) {} 48 49 virtual ~DomainReliabilityUploaderImpl() { 50 // Delete any in-flight URLFetchers. 51 STLDeleteContainerPairFirstPointers( 52 upload_callbacks_.begin(), upload_callbacks_.end()); 53 } 54 55 // DomainReliabilityUploader implementation: 56 virtual void UploadReport( 57 const std::string& report_json, 58 const GURL& upload_url, 59 const DomainReliabilityUploader::UploadCallback& callback) OVERRIDE { 60 VLOG(1) << "Uploading report to " << upload_url; 61 VLOG(2) << "Report JSON: " << report_json; 62 63 if (discard_uploads_) { 64 VLOG(1) << "Discarding report instead of uploading."; 65 callback.Run(true); 66 return; 67 } 68 69 net::URLFetcher* fetcher = 70 net::URLFetcher::Create(0, upload_url, net::URLFetcher::POST, this); 71 fetcher->SetRequestContext(url_request_context_getter_.get()); 72 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | 73 net::LOAD_DO_NOT_SAVE_COOKIES); 74 fetcher->SetUploadData(kJsonMimeType, report_json); 75 fetcher->SetAutomaticallyRetryOn5xx(false); 76 fetcher->SetURLRequestUserData( 77 UploadUserData::kUserDataKey, 78 UploadUserData::CreateCreateDataCallback()); 79 fetcher->Start(); 80 81 upload_callbacks_[fetcher] = callback; 82 } 83 84 virtual void set_discard_uploads(bool discard_uploads) OVERRIDE { 85 discard_uploads_ = discard_uploads; 86 VLOG(1) << "Setting discard_uploads to " << discard_uploads; 87 } 88 89 // net::URLFetcherDelegate implementation: 90 virtual void OnURLFetchComplete( 91 const net::URLFetcher* fetcher) OVERRIDE { 92 DCHECK(fetcher); 93 94 UploadCallbackMap::iterator callback_it = upload_callbacks_.find(fetcher); 95 DCHECK(callback_it != upload_callbacks_.end()); 96 97 VLOG(1) << "Upload finished with " << fetcher->GetResponseCode(); 98 99 UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.UploadResponseCode", 100 fetcher->GetResponseCode()); 101 102 bool success = fetcher->GetResponseCode() == 200; 103 callback_it->second.Run(success); 104 105 delete callback_it->first; 106 upload_callbacks_.erase(callback_it); 107 } 108 109 private: 110 using DomainReliabilityUploader::UploadCallback; 111 typedef std::map<const net::URLFetcher*, UploadCallback> UploadCallbackMap; 112 113 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; 114 UploadCallbackMap upload_callbacks_; 115 bool discard_uploads_; 116 }; 117 118 } // namespace 119 120 DomainReliabilityUploader::DomainReliabilityUploader() {} 121 DomainReliabilityUploader::~DomainReliabilityUploader() {} 122 123 // static 124 scoped_ptr<DomainReliabilityUploader> DomainReliabilityUploader::Create( 125 const scoped_refptr<net::URLRequestContextGetter>& 126 url_request_context_getter) { 127 return scoped_ptr<DomainReliabilityUploader>( 128 new DomainReliabilityUploaderImpl(url_request_context_getter)); 129 } 130 131 // static 132 bool DomainReliabilityUploader::URLRequestIsUpload( 133 const net::URLRequest& request) { 134 return request.GetUserData(UploadUserData::kUserDataKey) != NULL; 135 } 136 137 } // namespace domain_reliability 138