// 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