web_resource_service.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2010 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.
43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/web_resource/web_resource_service.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h"
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_path.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_util.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/values.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
15731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/browser_thread.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/net/url_fetcher.h"
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/notification_service.h"
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/notification_type.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/load_flags.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_status.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char* WebResourceService::kCurrentTipPrefName = "current_tip";
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char* WebResourceService::kTipCachePrefName = "tips";
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebResourceService::WebResourceFetcher
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public URLFetcher::Delegate {
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit WebResourceFetcher(WebResourceService* web_resource_service) :
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_factory_(this)),
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      web_resource_service_(web_resource_service) {
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Delay initial load of resource data into cache so as not to interfere
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // with startup time.
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void StartAfterDelay(int delay_ms) {
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostDelayedTask(FROM_HERE,
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         delay_ms);
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Initializes the fetching of data from the resource server.  Data
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // load calls OnURLFetchComplete.
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void StartFetch() {
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Balanced in OnURLFetchComplete.
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    web_resource_service_->AddRef();
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // First, put our next cache load on the MessageLoop.
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostDelayedTask(FROM_HERE,
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         kCacheUpdateDelay);
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we are still fetching data, exit.
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (web_resource_service_->in_fetch_)
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      web_resource_service_->in_fetch_ = true;
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_.reset(new URLFetcher(GURL(
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        web_resource_service_->web_resource_server_),
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        URLFetcher::GET, this));
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Do not let url fetcher affect existing state in profile (by setting
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // cookies, for example.
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_->set_load_flags(net::LOAD_DISABLE_CACHE |
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net::LOAD_DO_NOT_SAVE_COOKIES);
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_->set_request_context(Profile::GetDefaultRequestContext());
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_->Start();
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // From URLFetcher::Delegate.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void OnURLFetchComplete(const URLFetcher* source,
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const GURL& url,
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const URLRequestStatus& status,
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          int response_code,
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const ResponseCookies& cookies,
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const std::string& data) {
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Delete the URLFetcher when this function exits.
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<URLFetcher> clean_up_fetcher(url_fetcher_.release());
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't parse data if attempt to download was unsuccessful.
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Stop loading new web resource data, and silently exit.
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!status.is_success() || (response_code != 200))
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->UpdateResourceCache(data);
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    web_resource_service_->Release();
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // So that we can delay our start so as not to affect start-up time; also,
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // so that we can schedule future cache updates.
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedRunnableMethodFactory<WebResourceFetcher> fetcher_factory_;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tool that fetches the url data from the server.
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<URLFetcher> url_fetcher_;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Our owner and creator. Ref counted.
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  WebResourceService* web_resource_service_;
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class coordinates a web resource unpack and parse task which is run in
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// a separate process.  Results are sent back to this class and routed to
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the WebResourceService.
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebResourceService::UnpackerClient
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public UtilityProcessHost::Client {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UnpackerClient(WebResourceService* web_resource_service,
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 const std::string& json_data)
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : web_resource_service_(web_resource_service),
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      json_data_(json_data), got_response_(false) {
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Start() {
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddRef();  // balanced in Cleanup.
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we don't have a resource_dispatcher_host_, assume we're in
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // a test and run the unpacker directly in-process.
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool use_utility_process =
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        web_resource_service_->resource_dispatcher_host_ != NULL &&
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (use_utility_process) {
123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::ID thread_id;
124731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_id));
125731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::IO, FROM_HERE,
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NewRunnableMethod(this, &UnpackerClient::StartProcessOnIOThread,
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            web_resource_service_->resource_dispatcher_host_,
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            thread_id));
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      WebResourceUnpacker unpacker(json_data_);
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (unpacker.Run()) {
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        OnUnpackWebResourceSucceeded(*unpacker.parsed_json());
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        OnUnpackWebResourceFailed(unpacker.error_message());
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~UnpackerClient() {}
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // UtilityProcessHost::Client
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnProcessCrashed() {
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (got_response_)
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnUnpackWebResourceFailed(
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "Chrome crashed while trying to retrieve web resources.");
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnUnpackWebResourceSucceeded(
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const DictionaryValue& parsed_json) {
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->OnWebResourceUnpacked(parsed_json);
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cleanup();
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnUnpackWebResourceFailed(const std::string& error_message) {
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->EndFetch();
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cleanup();
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Release reference and set got_response_.
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Cleanup() {
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (got_response_)
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    got_response_ = true;
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Release();
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void StartProcessOnIOThread(ResourceDispatcherHost* rdh,
173731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              BrowserThread::ID thread_id) {
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UtilityProcessHost* host = new UtilityProcessHost(rdh, this, thread_id);
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(mrc): get proper file path when we start using web resources
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // that need to be unpacked.
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    host->StartWebResourceUnpacker(json_data_);
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<WebResourceService> web_resource_service_;
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Holds raw JSON string.
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string& json_data_;
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // True if we got a response from the utility process and have cleaned up
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // already.
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool got_response_;
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Server for custom logo signals.
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* WebResourceService::kDefaultResourceServer =
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    "https://www.google.com/support/chrome/bin/topic/30248/inproduct";
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebResourceService::WebResourceService(Profile* profile)
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : prefs_(profile->GetPrefs()),
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      in_fetch_(false) {
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Init();
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebResourceService::~WebResourceService() { }
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::Init() {
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resource_dispatcher_host_ = g_browser_process->resource_dispatcher_host();
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  web_resource_fetcher_.reset(new WebResourceFetcher(this));
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  prefs_->RegisterStringPref(prefs::kNTPWebResourceCacheUpdate, "0");
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  prefs_->RegisterRealPref(prefs::kNTPCustomLogoStart, 0);
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  prefs_->RegisterRealPref(prefs::kNTPCustomLogoEnd, 0);
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (prefs_->HasPrefPath(prefs::kNTPLogoResourceServer)) {
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    web_resource_server_ = prefs_->GetString(prefs::kNTPLogoResourceServer);
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If we have not yet set a server, reset and force an immediate update.
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_server_ = kDefaultResourceServer;
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  prefs_->SetString(prefs::kNTPWebResourceCacheUpdate, "");
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::EndFetch() {
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  in_fetch_ = false;
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::OnWebResourceUnpacked(
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const DictionaryValue& parsed_json) {
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  UnpackLogoSignal(parsed_json);
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EndFetch();
2273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WebResourceService::StartAfterDelay() {
2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int delay = kStartResourceFetchDelay;
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Check whether we have ever put a value in the web resource cache;
2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // if so, pull it out and see if it's time to update again.
2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (prefs_->HasPrefPath(prefs::kNTPWebResourceCacheUpdate)) {
2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string last_update_pref =
2353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        prefs_->GetString(prefs::kNTPWebResourceCacheUpdate);
2363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!last_update_pref.empty()) {
2373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      double last_update_value;
2383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      base::StringToDouble(last_update_pref, &last_update_value);
2393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      int ms_until_update = kCacheUpdateDelay -
2403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          static_cast<int>((base::Time::Now() - base::Time::FromDoubleT(
2413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          last_update_value)).InMilliseconds());
2423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      delay = ms_until_update > kCacheUpdateDelay ?
2443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick              kCacheUpdateDelay : (ms_until_update < kStartResourceFetchDelay ?
2453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   kStartResourceFetchDelay : ms_until_update);
2463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
2473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Start fetch and wait for UpdateResourceCache.
2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  web_resource_fetcher_->StartAfterDelay(static_cast<int>(delay));
2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WebResourceService::UpdateResourceCache(const std::string& json_data) {
2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  UnpackerClient* client = new UnpackerClient(this, json_data);
2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  client->Start();
2563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Update resource server and cache update time in preferences.
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  prefs_->SetString(prefs::kNTPWebResourceCacheUpdate,
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      base::DoubleToString(base::Time::Now().ToDoubleT()));
2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  prefs_->SetString(prefs::kNTPLogoResourceServer, web_resource_server_);
2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WebResourceService::UnpackTips(const DictionaryValue& parsed_json) {
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get dictionary of cached preferences.
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_cache_ =
2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      prefs_->GetMutableDictionary(prefs::kNTPWebResourceCache);
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The list of individual tips.
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* tip_holder = new ListValue();
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_cache_->Set(WebResourceService::kTipCachePrefName, tip_holder);
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* topic_dict;
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* answer_list;
2743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string topic_id;
2753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string answer_id;
2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string inproduct;
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tip_counter = 0;
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (parsed_json.GetDictionary("topic", &topic_dict)) {
2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (topic_dict->GetString("topic_id", &topic_id))
2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      web_resource_cache_->SetString("topic_id", topic_id);
2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (topic_dict->GetList("answers", &answer_list)) {
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (ListValue::const_iterator tip_iter = answer_list->begin();
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           tip_iter != answer_list->end(); ++tip_iter) {
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY))
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          continue;
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DictionaryValue* a_dic =
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            static_cast<DictionaryValue*>(*tip_iter);
2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (a_dic->GetString("inproduct", &inproduct)) {
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          tip_holder->Append(Value::CreateStringValue(inproduct));
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tip_counter++;
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
2943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // If tips exist, set current index to 0.
2953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (!inproduct.empty()) {
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        web_resource_cache_->SetInteger(
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          WebResourceService::kCurrentTipPrefName, 0);
2983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WebResourceService::UnpackLogoSignal(const DictionaryValue& parsed_json) {
3043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DictionaryValue* topic_dict;
3053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ListValue* answer_list;
3063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  double old_logo_start = 0;
3073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  double old_logo_end = 0;
3083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  double logo_start = 0;
3093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  double logo_end = 0;
3103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Check for preexisting start and end values.
3123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (prefs_->HasPrefPath(prefs::kNTPCustomLogoStart) &&
3133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      prefs_->HasPrefPath(prefs::kNTPCustomLogoEnd)) {
3143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    old_logo_start = prefs_->GetReal(prefs::kNTPCustomLogoStart);
3153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    old_logo_end = prefs_->GetReal(prefs::kNTPCustomLogoEnd);
3163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Check for newly received start and end values.
3193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (parsed_json.GetDictionary("topic", &topic_dict)) {
3203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (topic_dict->GetList("answers", &answer_list)) {
3213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      std::string logo_start_string = "";
3223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      std::string logo_end_string = "";
3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      for (ListValue::const_iterator tip_iter = answer_list->begin();
3243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick           tip_iter != answer_list->end(); ++tip_iter) {
3253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY))
3263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          continue;
3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        DictionaryValue* a_dic =
3283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            static_cast<DictionaryValue*>(*tip_iter);
3293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        std::string logo_signal;
3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (a_dic->GetString("name", &logo_signal)) {
3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          if (logo_signal == "custom_logo_start") {
3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            a_dic->GetString("inproduct", &logo_start_string);
3333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          } else if (logo_signal == "custom_logo_end") {
3343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            a_dic->GetString("inproduct", &logo_end_string);
3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          }
3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        }
3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
3383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (!logo_start_string.empty() &&
3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          logo_start_string.length() > 0 &&
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          !logo_end_string.empty() &&
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          logo_end_string.length() > 0) {
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        base::Time start_time;
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        base::Time end_time;
3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (base::Time::FromString(
3453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                ASCIIToWide(logo_start_string).c_str(), &start_time) &&
3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            base::Time::FromString(
3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                ASCIIToWide(logo_end_string).c_str(), &end_time)) {
3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          logo_start = start_time.ToDoubleT();
3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          logo_end = end_time.ToDoubleT();
3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        }
3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
355731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // If logo start or end times have changed, trigger a new web resource
356731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // notification, so that the logo on the NTP is updated. This check is
357731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // outside the reading of the web resource data, because the absence of
358731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // dates counts as a triggering change if there were dates before.
3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!(old_logo_start == logo_start) ||
3603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      !(old_logo_end == logo_end)) {
3613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    prefs_->SetReal(prefs::kNTPCustomLogoStart, logo_start);
3623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    prefs_->SetReal(prefs::kNTPCustomLogoEnd, logo_end);
3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NotificationService* service = NotificationService::current();
364731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    service->Notify(NotificationType::WEB_RESOURCE_AVAILABLE,
3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                    Source<WebResourceService>(this),
3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                    NotificationService::NoDetails());
3673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
369