// 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 "base/bind.h" #include "base/callback.h" #include "base/memory/scoped_vector.h" #include "base/metrics/sparse_histogram.h" #include "base/stl_util.h" #include "base/supports_user_data.h" #include "net/base/load_flags.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_fetcher_delegate.h" #include "net/url_request/url_request_context_getter.h" namespace domain_reliability { namespace { const char* kJsonMimeType = "application/json; charset=utf-8"; class UploadUserData : public base::SupportsUserData::Data { public: static net::URLFetcher::CreateDataCallback CreateCreateDataCallback() { return base::Bind(&UploadUserData::CreateUploadUserData); } static const void* kUserDataKey; private: static base::SupportsUserData::Data* CreateUploadUserData() { return new UploadUserData(); } }; const void* UploadUserData::kUserDataKey = static_cast<const void*>(&UploadUserData::kUserDataKey); class DomainReliabilityUploaderImpl : public DomainReliabilityUploader, net::URLFetcherDelegate { public: DomainReliabilityUploaderImpl(const scoped_refptr< net::URLRequestContextGetter>& url_request_context_getter) : url_request_context_getter_(url_request_context_getter), discard_uploads_(true) {} virtual ~DomainReliabilityUploaderImpl() { // Delete any in-flight URLFetchers. STLDeleteContainerPairFirstPointers( upload_callbacks_.begin(), upload_callbacks_.end()); } // DomainReliabilityUploader implementation: virtual void UploadReport( const std::string& report_json, const GURL& upload_url, const DomainReliabilityUploader::UploadCallback& callback) OVERRIDE { VLOG(1) << "Uploading report to " << upload_url; VLOG(2) << "Report JSON: " << report_json; if (discard_uploads_) { VLOG(1) << "Discarding report instead of uploading."; callback.Run(true); return; } net::URLFetcher* fetcher = net::URLFetcher::Create(0, upload_url, net::URLFetcher::POST, this); fetcher->SetRequestContext(url_request_context_getter_.get()); fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); fetcher->SetUploadData(kJsonMimeType, report_json); fetcher->SetAutomaticallyRetryOn5xx(false); fetcher->SetURLRequestUserData( UploadUserData::kUserDataKey, UploadUserData::CreateCreateDataCallback()); fetcher->Start(); upload_callbacks_[fetcher] = callback; } virtual void set_discard_uploads(bool discard_uploads) OVERRIDE { discard_uploads_ = discard_uploads; VLOG(1) << "Setting discard_uploads to " << discard_uploads; } // net::URLFetcherDelegate implementation: virtual void OnURLFetchComplete( const net::URLFetcher* fetcher) OVERRIDE { DCHECK(fetcher); UploadCallbackMap::iterator callback_it = upload_callbacks_.find(fetcher); DCHECK(callback_it != upload_callbacks_.end()); VLOG(1) << "Upload finished with " << fetcher->GetResponseCode(); UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.UploadResponseCode", fetcher->GetResponseCode()); bool success = fetcher->GetResponseCode() == 200; callback_it->second.Run(success); delete callback_it->first; upload_callbacks_.erase(callback_it); } private: using DomainReliabilityUploader::UploadCallback; typedef std::map<const net::URLFetcher*, UploadCallback> UploadCallbackMap; scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; UploadCallbackMap upload_callbacks_; bool discard_uploads_; }; } // namespace DomainReliabilityUploader::DomainReliabilityUploader() {} DomainReliabilityUploader::~DomainReliabilityUploader() {} // static scoped_ptr<DomainReliabilityUploader> DomainReliabilityUploader::Create( const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter) { return scoped_ptr<DomainReliabilityUploader>( new DomainReliabilityUploaderImpl(url_request_context_getter)); } // static bool DomainReliabilityUploader::URLRequestIsUpload( const net::URLRequest& request) { return request.GetUserData(UploadUserData::kUserDataKey) != NULL; } } // namespace domain_reliability