This source file includes following definitions.
- upload_interval_
- QueueLog
- IsUploadScheduled
- ScheduleNextUpload
- StartScheduledUpload
- BackOffUploadInterval
- OnURLFetchComplete
- OnUploadFinished
#include "components/rappor/log_uploader.h"
#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_fetcher.h"
namespace {
const int kUnsentLogsIntervalSeconds = 3;
const double kBackoffMultiplier = 1.1;
const int kMaxBackoffIntervalSeconds = 60 * 60;
const size_t kMaxQueuedLogs = 10;
enum DiscardReason {
UPLOAD_SUCCESS,
UPLOAD_REJECTED,
QUEUE_OVERFLOW,
NUM_DISCARD_REASONS
};
}
namespace rappor {
LogUploader::LogUploader(const GURL& server_url,
const std::string& mime_type,
net::URLRequestContextGetter* request_context)
: server_url_(server_url),
mime_type_(mime_type),
request_context_(request_context),
has_callback_pending_(false),
upload_interval_(base::TimeDelta::FromSeconds(
kUnsentLogsIntervalSeconds)) {
}
LogUploader::~LogUploader() {}
void LogUploader::QueueLog(const std::string& log) {
queued_logs_.push(log);
if (!IsUploadScheduled() && !has_callback_pending_)
StartScheduledUpload();
}
bool LogUploader::IsUploadScheduled() const {
return upload_timer_.IsRunning();
}
void LogUploader::ScheduleNextUpload(base::TimeDelta interval) {
if (IsUploadScheduled() || has_callback_pending_)
return;
upload_timer_.Start(
FROM_HERE, interval, this, &LogUploader::StartScheduledUpload);
}
void LogUploader::StartScheduledUpload() {
DCHECK(!has_callback_pending_);
has_callback_pending_ = true;
current_fetch_.reset(
net::URLFetcher::Create(server_url_, net::URLFetcher::POST, this));
current_fetch_->SetRequestContext(request_context_.get());
current_fetch_->SetUploadData(mime_type_, queued_logs_.front());
current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
net::LOAD_DO_NOT_SEND_COOKIES);
current_fetch_->Start();
}
base::TimeDelta LogUploader::BackOffUploadInterval(base::TimeDelta interval) {
DCHECK_GT(kBackoffMultiplier, 1.0);
interval = base::TimeDelta::FromMicroseconds(static_cast<int64>(
kBackoffMultiplier * interval.InMicroseconds()));
base::TimeDelta max_interval =
base::TimeDelta::FromSeconds(kMaxBackoffIntervalSeconds);
return interval > max_interval ? max_interval : interval;
}
void LogUploader::OnURLFetchComplete(const net::URLFetcher* source) {
DCHECK_EQ(current_fetch_.get(), source);
scoped_ptr<net::URLFetcher> fetch(current_fetch_.Pass());
const int response_code = source->GetResponseCode();
UMA_HISTOGRAM_SPARSE_SLOWLY("Rappor.UploadResponseCode", response_code);
const bool upload_succeeded = response_code == 200;
DiscardReason reason = NUM_DISCARD_REASONS;
if (upload_succeeded) {
reason = UPLOAD_SUCCESS;
} else if (response_code == 400) {
reason = UPLOAD_REJECTED;
} else if (queued_logs_.size() > kMaxQueuedLogs) {
reason = QUEUE_OVERFLOW;
}
if (reason != NUM_DISCARD_REASONS) {
UMA_HISTOGRAM_ENUMERATION("Rappor.DiscardReason",
reason,
NUM_DISCARD_REASONS);
queued_logs_.pop();
}
const bool server_is_healthy = upload_succeeded || response_code == 400;
OnUploadFinished(server_is_healthy, !queued_logs_.empty());
}
void LogUploader::OnUploadFinished(bool server_is_healthy,
bool more_logs_remaining) {
DCHECK(has_callback_pending_);
has_callback_pending_ = false;
if (!server_is_healthy)
upload_interval_ = BackOffUploadInterval(upload_interval_);
else
upload_interval_ = base::TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds);
if (more_logs_remaining)
ScheduleNextUpload(upload_interval_);
}
}