web_history_service.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/web_history_service.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_reader.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_writer.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/utf_string_conversions.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/signin/oauth2_token_service.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/signin/oauth2_token_service_factory.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "googleurl/src/gurl.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/load_flags.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/url_util.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/http/http_status_code.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_fetcher.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace history {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kHistoryOAuthScope[] =
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "https://www.googleapis.com/auth/chromesync";
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kHistoryQueryHistoryUrl[] =
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "https://history.google.com/history/api/lookup?client=chrome";
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kHistoryDeleteHistoryUrl[] =
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "https://history.google.com/history/api/delete?client=chrome";
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kPostDataMimeType[] = "text/plain";
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The maximum number of retries for the URLFetcher requests.
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMaxRetries = 1;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class RequestImpl : public WebHistoryService::Request,
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    private OAuth2TokenService::Consumer,
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    private net::URLFetcherDelegate {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~RequestImpl() {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns the response code received from the server, which will only be
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // valid if the request succeeded.
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int response_code() { return response_code_; }
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns the contents of the response body received from the server.
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string& response_body() { return response_body_; }
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  friend class history::WebHistoryService;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef base::Callback<void(Request*, bool)> CompletionCallback;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RequestImpl(Profile* profile,
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              const std::string& url,
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              const CompletionCallback& callback)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : profile_(profile),
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url_(GURL(url)),
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        response_code_(0),
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        callback_(callback) {
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Tells the request to do its thang.
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Start() {
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OAuth2TokenService::ScopeSet oauth_scopes;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    oauth_scopes.insert(kHistoryOAuthScope);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OAuth2TokenService* token_service =
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        OAuth2TokenServiceFactory::GetForProfile(profile_);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    token_request_ = token_service->StartRequest(oauth_scopes, this);
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // content::URLFetcherDelegate interface.
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(source, url_fetcher_.get());
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    response_code_ = url_fetcher_->GetResponseCode();
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    url_fetcher_->GetResponseAsString(&response_body_);
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    url_fetcher_.reset();
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback_.Run(this, true);
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // OAuth2TokenService::Consumer interface.
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnGetTokenSuccess(
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const OAuth2TokenService::Request* request,
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& access_token,
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const base::Time& expiration_time) OVERRIDE {
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    token_request_.reset();
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(!access_token.empty());
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Got an access token -- start the actual API request.
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    url_fetcher_.reset(CreateUrlFetcher(access_token));
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    url_fetcher_->Start();
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnGetTokenFailure(
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const OAuth2TokenService::Request* request,
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const GoogleServiceAuthError& error) OVERRIDE {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    token_request_.reset();
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Failed to get OAuth token: " << error.ToString();
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback_.Run(this, false);
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Helper for creating a new URLFetcher for the API request.
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::URLFetcher* CreateUrlFetcher(const std::string& access_token) {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLFetcher::RequestType request_type = post_data_.empty() ?
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        net::URLFetcher::GET : net::URLFetcher::POST;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLFetcher* fetcher = net::URLFetcher::Create(
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url_, request_type, this);
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    fetcher->SetRequestContext(profile_->GetRequestContext());
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    fetcher->SetMaxRetriesOn5xx(kMaxRetries);
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          net::LOAD_DO_NOT_SAVE_COOKIES);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    fetcher->AddExtraRequestHeader("Authorization: Bearer " + access_token);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    fetcher->AddExtraRequestHeader("X-Developer-Key: " +
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GaiaUrls::GetInstance()->oauth2_chrome_client_id());
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (request_type == net::URLFetcher::POST)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fetcher->SetUploadData(kPostDataMimeType, post_data_);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return fetcher;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void set_post_data(const std::string& post_data) {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    post_data_ = post_data;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Profile* profile_;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The URL of the API endpoint.
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GURL url_;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // POST data to be sent with the request (may be empty).
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string post_data_;
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The OAuth2 access token request.
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<OAuth2TokenService::Request> token_request_;
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Handles the actual API requests after the OAuth token is acquired.
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<net::URLFetcher> url_fetcher_;
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Holds the response code received from the server.
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int response_code_;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Holds the response body received from the server.
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string response_body_;
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The callback to execute when the query is complete.
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CompletionCallback callback_;
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Called when a query to web history has completed, successfully or not.
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void QueryHistoryCompletionCallback(
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const WebHistoryService::QueryWebHistoryCallback& callback,
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WebHistoryService::Request* request,
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool success) {
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RequestImpl* request_impl = static_cast<RequestImpl*>(request);
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (success && request_impl->response_code() == net::HTTP_OK) {
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<base::Value> value(
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::JSONReader::Read(request_impl->response_body()));
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (value.get() && value->IsType(base::Value::TYPE_DICTIONARY)) {
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      callback.Run(request, static_cast<DictionaryValue*>(value.get()));
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run(request, NULL);
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Converts a time into a string for use as a parameter in a request to the
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// history server.
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string ServerTimeString(base::Time time) {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::Int64ToString((time - base::Time::UnixEpoch()).InMicroseconds());
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns a URL for querying the history server for a query specified by
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |options|.
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string GetQueryUrl(const string16& text_query,
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        const QueryOptions& options) {
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GURL url = GURL(kHistoryQueryHistoryUrl);
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  url = net::AppendQueryParameter(url, "titles", "1");
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Take |begin_time|, |end_time|, and |max_count| from the original query
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // options, and convert them to the equivalent URL parameters.
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Time end_time =
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::min(base::Time::FromInternalValue(options.EffectiveEndTime()),
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               base::Time::Now());
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  url = net::AppendQueryParameter(url, "max", ServerTimeString(end_time));
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!options.begin_time.is_null()) {
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    url = net::AppendQueryParameter(
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url, "min", ServerTimeString(options.begin_time));
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (options.max_count) {
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    url = net::AppendQueryParameter(
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url, "num", base::IntToString(options.max_count));
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!text_query.empty())
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    url = net::AppendQueryParameter(url, "q", UTF16ToUTF8(text_query));
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return url.spec();
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Creates a DictionaryValue to hold the parameters for a deletion.
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Ownership is passed to the caller.
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |url| may be empty, indicating a time-range deletion.
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DictionaryValue* CreateDeletion(
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& min_time,
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& max_time,
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& url) {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryValue* deletion = new DictionaryValue;
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  deletion->SetString("type", "CHROME_HISTORY");
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (url.is_valid())
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    deletion->SetString("url", url.spec());
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  deletion->SetString("min_timestamp_usec", min_time);
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  deletion->SetString("max_timestamp_usec", max_time);
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return deletion;
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebHistoryService::Request::Request() {
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebHistoryService::Request::~Request() {
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebHistoryService::WebHistoryService(Profile* profile)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : profile_(profile) {
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebHistoryService::~WebHistoryService() {
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<WebHistoryService::Request> WebHistoryService::QueryHistory(
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const string16& text_query,
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const QueryOptions& options,
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const WebHistoryService::QueryWebHistoryCallback& callback) {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Wrap the original callback into a generic completion callback.
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RequestImpl::CompletionCallback completion_callback = base::Bind(
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &QueryHistoryCompletionCallback, callback);
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string url = GetQueryUrl(text_query, options);
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<RequestImpl> request(
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new RequestImpl(profile_, url, completion_callback));
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request->Start();
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return request.PassAs<Request>();
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<WebHistoryService::Request> WebHistoryService::ExpireHistory(
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<ExpireHistoryArgs>& expire_list,
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ExpireWebHistoryCallback& callback) {
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryValue delete_request;
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<ListValue> deletions(new ListValue);
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Time now = base::Time::Now();
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::vector<ExpireHistoryArgs>::const_iterator it = expire_list.begin();
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != expire_list.end(); ++it) {
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Convert the times to server timestamps.
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string min_timestamp = ServerTimeString(it->begin_time);
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(dubroy): Use sane time (crbug.com/146090) here when it's available.
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time end_time = it->end_time;
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (end_time.is_null() || end_time > now)
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      end_time = now;
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string max_timestamp = ServerTimeString(end_time);
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::set<GURL>::const_iterator url_iterator = it->urls.begin();
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         url_iterator != it->urls.end(); ++url_iterator) {
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      deletions->Append(
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          CreateDeletion(min_timestamp, max_timestamp, *url_iterator));
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If no URLs were specified, delete everything in the time range.
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->urls.empty())
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      deletions->Append(CreateDeletion(min_timestamp, max_timestamp, GURL()));
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete_request.Set("del", deletions.release());
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string post_data;
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::JSONWriter::Write(&delete_request, &post_data);
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<RequestImpl> request(
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new RequestImpl(profile_, kHistoryDeleteHistoryUrl, callback));
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request->set_post_data(post_data);
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request->Start();
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return request.PassAs<Request>();
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<WebHistoryService::Request> WebHistoryService::ExpireHistoryBetween(
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<GURL>& restrict_urls,
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time begin_time,
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time end_time,
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ExpireWebHistoryCallback& callback) {
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<ExpireHistoryArgs> expire_list(1);
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expire_list.back().urls = restrict_urls;
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expire_list.back().begin_time = begin_time;
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expire_list.back().end_time = end_time;
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ExpireHistory(expire_list, callback);
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace history
306