blob: c5f5cc1073402147f1a12a76dd0dc54ab883f76b [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS 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 "src/data_plan_provider.h"
#include <vector>
#include <base/json/json_reader.h> // NOLINT
#include <base/memory/scoped_ptr.h> // NOLINT
#include <base/values.h> // NOLINT
#include <glog/logging.h> // NOLINT
#include "src/libcurl_http_fetcher.h"
using std::vector;
namespace cashew {
DataPlanProvider::DataPlanProvider(const std::string& carrier)
: carrier_(carrier), delegate_(NULL),
fetcher_(CHECK_NOTNULL(new(std::nothrow) LibcurlHttpFetcher())),
request_in_progress_(false) {
fetcher_->set_delegate(this);
}
DataPlanProvider::~DataPlanProvider() {
CancelPendingRequests();
}
const std::string& DataPlanProvider::GetCarrier() const {
return carrier_;
}
const std::string& DataPlanProvider::GetUsageUrl() const {
return usage_url_;
}
void DataPlanProvider::SetUsageUrl(const std::string& usage_url) {
LOG(INFO) << carrier_ << ": SetUsageUrl: url = " << usage_url;
if (usage_url_ != usage_url) {
usage_url_ = usage_url;
CancelPendingRequests();
}
}
void DataPlanProvider::SetHttpProxy(const std::string& http_proxy) {
LOG(INFO) << carrier_ << ": SetHttpProxy: http_proxy = " << http_proxy;
if (http_proxy_ != http_proxy) {
http_proxy_ = http_proxy;
CancelPendingRequests();
}
}
void DataPlanProvider::SetDelegate(DataPlanProviderDelegate *delegate) {
LOG(INFO) << carrier_ << ": SetDelegate";
delegate_ = delegate;
if (delegate_ == NULL) {
CancelPendingRequests();
}
}
void DataPlanProvider::SetNameServers(const vector<std::string>& nameservers) {
fetcher_->set_nameservers(nameservers);
}
bool DataPlanProvider::RequestUsageUpdate() {
if (usage_url_.empty()) {
LOG(WARNING) << carrier_ << ": RequestUsageUpdate: no usage url";
return false;
}
if (delegate_ == NULL) {
LOG(WARNING) << carrier_ << ": RequestUsageUpdate: no delegate";
return false;
}
if (request_in_progress_) {
LOG(INFO) << carrier_
<< ": RequestUsageUpdate: request already in progress";
// we'll satisfy this request with the result from the in-flight one
return true;
}
DCHECK(response_buffer_.empty());
LOG(INFO) << carrier_ << ": RequestUsageUpdate: initiating request";
request_in_progress_ = true;
fetcher_->BeginTransfer(usage_url_, http_proxy_);
return true;
}
// HttpFetcherDelegate methods
void DataPlanProvider::ReceivedBytes(HttpFetcher *fetcher, const char *bytes,
int length) {
DCHECK(fetcher != NULL);
DCHECK(bytes != NULL);
DCHECK_GE(length, 0);
if (fetcher != fetcher_) {
LOG(WARNING) << carrier_ << ": ReceivedBytes: wrong fetcher";
return;
}
DCHECK(request_in_progress_);
LOG(INFO) << carrier_ << ": ReceivedBytes: length = " << length;
response_buffer_.reserve(response_buffer_.size() + length);
response_buffer_.insert(response_buffer_.end(), bytes, bytes + length);
}
void DataPlanProvider::TransferComplete(HttpFetcher *fetcher,
bool successful) {
DCHECK(fetcher != NULL);
if (fetcher != fetcher_) {
LOG(WARNING) << carrier_ << ": TransferComplete: wrong fetcher";
return;
}
DCHECK(request_in_progress_);
DCHECK(delegate_ != NULL);
LOG(INFO) << carrier_ << ": TransferComplete: result = " << successful;
if (!successful) {
LOG(WARNING) << carrier_ << ": TransferComplete: failed: response code = "
<< fetcher_->http_response_code();
response_buffer_.clear();
request_in_progress_ = false;
delegate_->OnRequestComplete(this, false, NULL);
return;
}
LOG(INFO) << carrier_ << ": TransferComplete: success: response code = "
<< fetcher_->http_response_code();
// carrier usage API has (we hope) given us a JSON-encoded result
// log it and then parse it, converting it into a tree of Value nodes
const std::string json_encoded_usage_update(response_buffer_.begin(),
response_buffer_.end());
response_buffer_.clear();
request_in_progress_ = false;
LOG(INFO) << carrier_ << ": TransferComplete: response:\n"
<< json_encoded_usage_update;
int error_code;
std::string error_msg;
scoped_ptr<Value> parsed_usage_update(
base::JSONReader::ReadAndReturnError(json_encoded_usage_update, true,
&error_code, &error_msg));
if (parsed_usage_update == NULL) {
LOG(WARNING) << carrier_ << ": TransferComplete: could not parse json: "
<< "error code " << error_code << ": " << error_msg;
delegate_->OnRequestComplete(this, false, NULL);
return;
}
LOG(INFO) << carrier_ << ": TransferComplete: successfully parsed json";
delegate_->OnRequestComplete(this, true, parsed_usage_update.get());
}
void DataPlanProvider::CancelPendingRequests() {
if (request_in_progress_) {
fetcher_->TerminateTransfer();
response_buffer_.clear();
request_in_progress_ = false;
}
}
// private methods
} // namespace cashew