This source file includes following definitions.
- response_code
- response_body
- is_pending
- Start
- OnURLFetchComplete
- OnGetTokenSuccess
- OnGetTokenFailure
- CreateUrlFetcher
- set_post_data
- ReadResponse
- ServerTimeString
- GetQueryUrl
- CreateDeletion
- weak_ptr_factory_
- QueryHistory
- ExpireHistory
- ExpireHistoryBetween
- QueryHistoryCompletionCallback
- ExpireHistoryCompletionCallback
#include "chrome/browser/history/web_history_service.h"
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_manager.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_token_service.h"
#include "net/base/load_flags.h"
#include "net/base/url_util.h"
#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "url/gurl.h"
namespace history {
namespace {
const char kHistoryOAuthScope[] =
"https://www.googleapis.com/auth/chromesync";
const char kHistoryQueryHistoryUrl[] =
"https://history.google.com/history/api/lookup?client=chrome";
const char kHistoryDeleteHistoryUrl[] =
"https://history.google.com/history/api/delete?client=chrome";
const char kPostDataMimeType[] = "text/plain";
const size_t kMaxRetries = 1;
class RequestImpl : public WebHistoryService::Request,
private OAuth2TokenService::Consumer,
private net::URLFetcherDelegate {
public:
virtual ~RequestImpl() {
}
int response_code() { return response_code_; }
const std::string& response_body() { return response_body_; }
virtual bool is_pending() OVERRIDE { return is_pending_; }
private:
friend class history::WebHistoryService;
typedef base::Callback<void(Request*, bool)> CompletionCallback;
RequestImpl(Profile* profile,
const GURL& url,
const CompletionCallback& callback)
: OAuth2TokenService::Consumer("web_history"),
profile_(profile),
url_(url),
response_code_(0),
auth_retry_count_(0),
callback_(callback),
is_pending_(false) {
}
void Start() {
OAuth2TokenService::ScopeSet oauth_scopes;
oauth_scopes.insert(kHistoryOAuthScope);
ProfileOAuth2TokenService* token_service =
ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
SigninManagerBase* signin_manager =
SigninManagerFactory::GetForProfile(profile_);
token_request_ = token_service->StartRequest(
signin_manager->GetAuthenticatedAccountId(), oauth_scopes, this);
is_pending_ = true;
}
virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
DCHECK_EQ(source, url_fetcher_.get());
response_code_ = url_fetcher_->GetResponseCode();
UMA_HISTOGRAM_CUSTOM_ENUMERATION("WebHistory.OAuthTokenResponseCode",
net::HttpUtil::MapStatusCodeForHistogram(response_code_),
net::HttpUtil::GetStatusCodesForHistogram());
if (response_code_ == net::HTTP_UNAUTHORIZED && ++auth_retry_count_ <= 1) {
OAuth2TokenService::ScopeSet oauth_scopes;
oauth_scopes.insert(kHistoryOAuthScope);
ProfileOAuth2TokenService* token_service =
ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
SigninManagerBase* signin_manager =
SigninManagerFactory::GetForProfile(profile_);
token_service->InvalidateToken(
signin_manager->GetAuthenticatedAccountId(),
oauth_scopes,
access_token_);
access_token_.clear();
Start();
return;
}
url_fetcher_->GetResponseAsString(&response_body_);
url_fetcher_.reset();
is_pending_ = false;
callback_.Run(this, true);
}
virtual void OnGetTokenSuccess(
const OAuth2TokenService::Request* request,
const std::string& access_token,
const base::Time& expiration_time) OVERRIDE {
token_request_.reset();
DCHECK(!access_token.empty());
access_token_ = access_token;
UMA_HISTOGRAM_BOOLEAN("WebHistory.OAuthTokenCompletion", true);
url_fetcher_.reset(CreateUrlFetcher(access_token));
url_fetcher_->Start();
}
virtual void OnGetTokenFailure(
const OAuth2TokenService::Request* request,
const GoogleServiceAuthError& error) OVERRIDE {
token_request_.reset();
is_pending_ = false;
UMA_HISTOGRAM_BOOLEAN("WebHistory.OAuthTokenCompletion", false);
callback_.Run(this, false);
}
net::URLFetcher* CreateUrlFetcher(const std::string& access_token) {
net::URLFetcher::RequestType request_type = post_data_.empty() ?
net::URLFetcher::GET : net::URLFetcher::POST;
net::URLFetcher* fetcher = net::URLFetcher::Create(
url_, request_type, this);
fetcher->SetRequestContext(profile_->GetRequestContext());
fetcher->SetMaxRetriesOn5xx(kMaxRetries);
fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SAVE_COOKIES);
fetcher->AddExtraRequestHeader("Authorization: Bearer " + access_token);
fetcher->AddExtraRequestHeader("X-Developer-Key: " +
GaiaUrls::GetInstance()->oauth2_chrome_client_id());
if (request_type == net::URLFetcher::POST)
fetcher->SetUploadData(kPostDataMimeType, post_data_);
return fetcher;
}
void set_post_data(const std::string& post_data) {
post_data_ = post_data;
}
Profile* profile_;
GURL url_;
std::string post_data_;
scoped_ptr<OAuth2TokenService::Request> token_request_;
std::string access_token_;
scoped_ptr<net::URLFetcher> url_fetcher_;
int response_code_;
std::string response_body_;
int auth_retry_count_;
CompletionCallback callback_;
bool is_pending_;
};
scoped_ptr<base::DictionaryValue> ReadResponse(RequestImpl* request) {
scoped_ptr<base::DictionaryValue> result;
if (request->response_code() == net::HTTP_OK) {
base::Value* value = base::JSONReader::Read(request->response_body());
if (value && value->IsType(base::Value::TYPE_DICTIONARY))
result.reset(static_cast<base::DictionaryValue*>(value));
else
DLOG(WARNING) << "Non-JSON response received from history server.";
}
return result.Pass();
}
std::string ServerTimeString(base::Time time) {
if (time < base::Time::UnixEpoch()) {
return base::Int64ToString(0);
} else {
return base::Int64ToString(
(time - base::Time::UnixEpoch()).InMicroseconds());
}
}
GURL GetQueryUrl(const base::string16& text_query,
const QueryOptions& options,
const std::string& version_info) {
GURL url = GURL(kHistoryQueryHistoryUrl);
url = net::AppendQueryParameter(url, "titles", "1");
base::Time end_time =
std::min(base::Time::FromInternalValue(options.EffectiveEndTime()),
base::Time::Now());
url = net::AppendQueryParameter(url, "max", ServerTimeString(end_time));
if (!options.begin_time.is_null()) {
url = net::AppendQueryParameter(
url, "min", ServerTimeString(options.begin_time));
}
if (options.max_count) {
url = net::AppendQueryParameter(
url, "num", base::IntToString(options.max_count));
}
if (!text_query.empty())
url = net::AppendQueryParameter(url, "q", base::UTF16ToUTF8(text_query));
if (!version_info.empty())
url = net::AppendQueryParameter(url, "kvi", version_info);
return url;
}
base::DictionaryValue* CreateDeletion(
const std::string& min_time,
const std::string& max_time,
const GURL& url) {
base::DictionaryValue* deletion = new base::DictionaryValue;
deletion->SetString("type", "CHROME_HISTORY");
if (url.is_valid())
deletion->SetString("url", url.spec());
deletion->SetString("min_timestamp_usec", min_time);
deletion->SetString("max_timestamp_usec", max_time);
return deletion;
}
}
WebHistoryService::Request::Request() {
}
WebHistoryService::Request::~Request() {
}
WebHistoryService::WebHistoryService(Profile* profile)
: profile_(profile),
weak_ptr_factory_(this) {
}
WebHistoryService::~WebHistoryService() {
STLDeleteElements(&pending_expire_requests_);
}
scoped_ptr<WebHistoryService::Request> WebHistoryService::QueryHistory(
const base::string16& text_query,
const QueryOptions& options,
const WebHistoryService::QueryWebHistoryCallback& callback) {
RequestImpl::CompletionCallback completion_callback = base::Bind(
&WebHistoryService::QueryHistoryCompletionCallback, callback);
GURL url = GetQueryUrl(text_query, options, server_version_info_);
scoped_ptr<RequestImpl> request(
new RequestImpl(profile_, url, completion_callback));
request->Start();
return request.PassAs<Request>();
}
void WebHistoryService::ExpireHistory(
const std::vector<ExpireHistoryArgs>& expire_list,
const ExpireWebHistoryCallback& callback) {
base::DictionaryValue delete_request;
scoped_ptr<base::ListValue> deletions(new base::ListValue);
base::Time now = base::Time::Now();
for (std::vector<ExpireHistoryArgs>::const_iterator it = expire_list.begin();
it != expire_list.end(); ++it) {
std::string min_timestamp = ServerTimeString(it->begin_time);
base::Time end_time = it->end_time;
if (end_time.is_null() || end_time > now)
end_time = now;
std::string max_timestamp = ServerTimeString(end_time);
for (std::set<GURL>::const_iterator url_iterator = it->urls.begin();
url_iterator != it->urls.end(); ++url_iterator) {
deletions->Append(
CreateDeletion(min_timestamp, max_timestamp, *url_iterator));
}
if (it->urls.empty())
deletions->Append(CreateDeletion(min_timestamp, max_timestamp, GURL()));
}
delete_request.Set("del", deletions.release());
std::string post_data;
base::JSONWriter::Write(&delete_request, &post_data);
GURL url(kHistoryDeleteHistoryUrl);
if (!server_version_info_.empty())
url = net::AppendQueryParameter(url, "kvi", server_version_info_);
RequestImpl::CompletionCallback completion_callback =
base::Bind(&WebHistoryService::ExpireHistoryCompletionCallback,
weak_ptr_factory_.GetWeakPtr(),
callback);
scoped_ptr<RequestImpl> request(
new RequestImpl(profile_, url, completion_callback));
request->set_post_data(post_data);
request->Start();
pending_expire_requests_.insert(request.release());
}
void WebHistoryService::ExpireHistoryBetween(
const std::set<GURL>& restrict_urls,
base::Time begin_time,
base::Time end_time,
const ExpireWebHistoryCallback& callback) {
std::vector<ExpireHistoryArgs> expire_list(1);
expire_list.back().urls = restrict_urls;
expire_list.back().begin_time = begin_time;
expire_list.back().end_time = end_time;
ExpireHistory(expire_list, callback);
}
void WebHistoryService::QueryHistoryCompletionCallback(
const WebHistoryService::QueryWebHistoryCallback& callback,
WebHistoryService::Request* request,
bool success) {
scoped_ptr<base::DictionaryValue> response_value;
if (success)
response_value = ReadResponse(static_cast<RequestImpl*>(request));
callback.Run(request, response_value.get());
}
void WebHistoryService::ExpireHistoryCompletionCallback(
const WebHistoryService::ExpireWebHistoryCallback& callback,
WebHistoryService::Request* request,
bool success) {
scoped_ptr<base::DictionaryValue> response_value;
if (success) {
response_value = ReadResponse(static_cast<RequestImpl*>(request));
if (response_value)
response_value->GetString("version_info", &server_version_info_);
}
callback.Run(response_value.get() && success);
pending_expire_requests_.erase(request);
delete request;
}
}