web_resource_service.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/web_resource/web_resource_service.h"
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h"
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/values.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chrome_thread.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/net/url_fetcher.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/load_flags.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_status.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst wchar_t* WebResourceService::kCurrentTipPrefName = L"current_tip";
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst wchar_t* WebResourceService::kTipCachePrefName = L"tips";
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebResourceService::WebResourceFetcher
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public URLFetcher::Delegate {
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit WebResourceFetcher(WebResourceService* web_resource_service) :
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_factory_(this)),
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      web_resource_service_(web_resource_service) {
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Delay initial load of resource data into cache so as not to interfere
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // with startup time.
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void StartAfterDelay(int delay_ms) {
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostDelayedTask(FROM_HERE,
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         delay_ms);
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Initializes the fetching of data from the resource server.  Data
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // load calls OnURLFetchComplete.
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void StartFetch() {
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // First, put our next cache load on the MessageLoop.
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostDelayedTask(FROM_HERE,
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         kCacheUpdateDelay);
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we are still fetching data, exit.
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (web_resource_service_->in_fetch_)
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      web_resource_service_->in_fetch_ = true;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_.reset(new URLFetcher(GURL(
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        web_resource_service_->web_resource_server_),
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        URLFetcher::GET, this));
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Do not let url fetcher affect existing state in profile (by setting
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // cookies, for example.
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_->set_load_flags(net::LOAD_DISABLE_CACHE |
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net::LOAD_DO_NOT_SAVE_COOKIES);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_->set_request_context(Profile::GetDefaultRequestContext());
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_->Start();
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // From URLFetcher::Delegate.
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void OnURLFetchComplete(const URLFetcher* source,
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const GURL& url,
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const URLRequestStatus& status,
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          int response_code,
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const ResponseCookies& cookies,
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const std::string& data) {
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Delete the URLFetcher when this function exits.
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<URLFetcher> clean_up_fetcher(url_fetcher_.release());
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't parse data if attempt to download was unsuccessful.
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Stop loading new web resource data, and silently exit.
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!status.is_success() || (response_code != 200))
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->UpdateResourceCache(data);
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // So that we can delay our start so as not to affect start-up time; also,
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // so that we can schedule future cache updates.
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedRunnableMethodFactory<WebResourceFetcher> fetcher_factory_;
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tool that fetches the url data from the server.
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<URLFetcher> url_fetcher_;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Our owner and creator.
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<WebResourceService> web_resource_service_;
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class coordinates a web resource unpack and parse task which is run in
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// a separate process.  Results are sent back to this class and routed to
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the WebResourceService.
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebResourceService::UnpackerClient
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public UtilityProcessHost::Client {
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UnpackerClient(WebResourceService* web_resource_service,
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 const std::string& json_data)
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : web_resource_service_(web_resource_service),
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      json_data_(json_data), got_response_(false) {
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Start() {
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddRef();  // balanced in Cleanup.
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we don't have a resource_dispatcher_host_, assume we're in
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // a test and run the unpacker directly in-process.
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool use_utility_process =
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        web_resource_service_->resource_dispatcher_host_ != NULL &&
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (use_utility_process) {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ChromeThread::ID thread_id;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CHECK(ChromeThread::GetCurrentThreadIdentifier(&thread_id));
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ChromeThread::PostTask(
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ChromeThread::IO, FROM_HERE,
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NewRunnableMethod(this, &UnpackerClient::StartProcessOnIOThread,
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            web_resource_service_->resource_dispatcher_host_,
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            thread_id));
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      WebResourceUnpacker unpacker(json_data_);
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (unpacker.Run()) {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        OnUnpackWebResourceSucceeded(*unpacker.parsed_json());
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        OnUnpackWebResourceFailed(unpacker.error_message());
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~UnpackerClient() {}
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // UtilityProcessHost::Client
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnProcessCrashed() {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (got_response_)
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnUnpackWebResourceFailed(
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "Chrome crashed while trying to retrieve web resources.");
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnUnpackWebResourceSucceeded(
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const DictionaryValue& parsed_json) {
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->OnWebResourceUnpacked(parsed_json);
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cleanup();
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnUnpackWebResourceFailed(const std::string& error_message) {
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->EndFetch();
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cleanup();
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Release reference and set got_response_.
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Cleanup() {
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (got_response_)
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    got_response_ = true;
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Release();
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void StartProcessOnIOThread(ResourceDispatcherHost* rdh,
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              ChromeThread::ID thread_id) {
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UtilityProcessHost* host = new UtilityProcessHost(rdh, this, thread_id);
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(mrc): get proper file path when we start using web resources
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // that need to be unpacked.
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    host->StartWebResourceUnpacker(json_data_);
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<WebResourceService> web_resource_service_;
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Holds raw JSON string.
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string& json_data_;
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // True if we got a response from the utility process and have cleaned up
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // already.
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool got_response_;
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(mirandac): replace these servers tomorrow!
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* WebResourceService::kDefaultResourceServer =
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX)
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "https://clients2.google.com/tools/service/npredir?r=chrometips_mac&hl=";
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_LINUX)
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "https://clients2.google.com/tools/service/npredir?r=chrometips_linux&hl=";
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "https://clients2.google.com/tools/service/npredir?r=chrometips_win&hl=";
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* WebResourceService::kResourceDirectoryName =
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    "Resources";
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebResourceService::WebResourceService(Profile* profile)
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : prefs_(profile->GetPrefs()),
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      web_resource_dir_(profile->GetPath().AppendASCII(kResourceDirectoryName)),
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      in_fetch_(false) {
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Init();
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebResourceService::~WebResourceService() { }
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::Init() {
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resource_dispatcher_host_ = g_browser_process->resource_dispatcher_host();
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_fetcher_ = new WebResourceFetcher(this);
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs_->RegisterStringPref(prefs::kNTPTipsCacheUpdate, "0");
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string locale = g_browser_process->GetApplicationLocale();
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (prefs_->HasPrefPath(prefs::kNTPTipsServer)) {
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch     web_resource_server_ = prefs_->GetString(prefs::kNTPTipsServer);
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch     // If we are in the correct locale, initialization is done.
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch     if (EndsWith(web_resource_server_, locale, false))
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       return;
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we have not yet set a server, or if the tips server is set to the wrong
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // locale, reset the server and force an immediate update of tips.
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_server_ = kDefaultResourceServer;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_server_.append(locale);
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs_->SetString(prefs::kNTPTipsCacheUpdate, "");
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::EndFetch() {
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  in_fetch_ = false;
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::OnWebResourceUnpacked(
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const DictionaryValue& parsed_json) {
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get dictionary of cached preferences.
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_cache_ =
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      prefs_->GetMutableDictionary(prefs::kNTPTipsCache);
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The list of individual tips.
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* tip_holder = new ListValue();
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_cache_->Set(WebResourceService::kTipCachePrefName, tip_holder);
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* topic_dict;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* answer_list;
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring topic_id;
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring inproduct;
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tip_counter = 0;
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (parsed_json.GetDictionary(L"topic", &topic_dict)) {
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (topic_dict->GetString(L"topic_id", &topic_id))
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      web_resource_cache_->SetString(L"topic_id", topic_id);
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (topic_dict->GetList(L"answers", &answer_list)) {
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (ListValue::const_iterator tip_iter = answer_list->begin();
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           tip_iter != answer_list->end(); ++tip_iter) {
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY))
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          continue;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DictionaryValue* a_dic =
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            static_cast<DictionaryValue*>(*tip_iter);
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (a_dic->GetString(L"inproduct", &inproduct)) {
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          tip_holder->Append(Value::CreateStringValue(inproduct));
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tip_counter++;
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If we have tips, set current tip to zero.
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!inproduct.empty())
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        web_resource_cache_->SetInteger(
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          WebResourceService::kCurrentTipPrefName, 0);
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EndFetch();
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::StartAfterDelay() {
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int delay = kStartResourceFetchDelay;
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check whether we have ever put a value in the web resource cache;
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // if so, pull it out and see if it's time to update again.
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (prefs_->HasPrefPath(prefs::kNTPTipsCacheUpdate)) {
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string last_update_pref =
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      prefs_->GetString(prefs::kNTPTipsCacheUpdate);
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!last_update_pref.empty()) {
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int ms_until_update = kCacheUpdateDelay -
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          static_cast<int>((base::Time::Now() - base::Time::FromDoubleT(
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          StringToDouble(last_update_pref))).InMilliseconds());
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delay = ms_until_update > kCacheUpdateDelay ?
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kCacheUpdateDelay : (ms_until_update < kStartResourceFetchDelay ?
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   kStartResourceFetchDelay : ms_until_update);
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Start fetch and wait for UpdateResourceCache.
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_fetcher_->StartAfterDelay(static_cast<int>(delay));
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::UpdateResourceCache(const std::string& json_data) {
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UnpackerClient* client = new UnpackerClient(this, json_data);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  client->Start();
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update resource server and cache update time in preferences.
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs_->SetString(prefs::kNTPTipsCacheUpdate,
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DoubleToString(base::Time::Now().ToDoubleT()));
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs_->SetString(prefs::kNTPTipsServer, web_resource_server_);
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
298