172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 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_number_conversions.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/string_util.h"
1172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/threading/thread_restrictions.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/values.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/prefs/pref_service.h"
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
18201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/browser/sync/sync_ui_util.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h"
20201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/common/extensions/extension.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/net/url_fetcher.h"
22dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/common/web_resource/web_resource_unpacker.h"
23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/load_flags.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_status.h"
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.
3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  void StartAfterDelay(int64 delay_ms) {
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostDelayedTask(FROM_HERE,
41dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
42dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                           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,
52201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            web_resource_service_->cache_update_delay_);
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
60dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string web_resource_server =
61dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        web_resource_service_->web_resource_server_;
62dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (web_resource_service_->apply_locale_to_url_) {
63dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      std::string locale = g_browser_process->GetApplicationLocale();
64dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      web_resource_server.append(locale);
65dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_.reset(new URLFetcher(GURL(
6872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        web_resource_server),
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        URLFetcher::GET, this));
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Do not let url fetcher affect existing state in profile (by setting
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // cookies, for example.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_->set_load_flags(net::LOAD_DISABLE_CACHE |
73dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        net::LOAD_DO_NOT_SAVE_COOKIES);
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    net::URLRequestContextGetter* url_request_context_getter =
75dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        web_resource_service_->profile_->GetRequestContext();
7672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    url_fetcher_->set_request_context(url_request_context_getter);
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_->Start();
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // From URLFetcher::Delegate.
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void OnURLFetchComplete(const URLFetcher* source,
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const GURL& url,
8372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                          const net::URLRequestStatus& status,
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          int response_code,
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const ResponseCookies& cookies,
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const std::string& data) {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Delete the URLFetcher when this function exits.
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<URLFetcher> clean_up_fetcher(url_fetcher_.release());
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't parse data if attempt to download was unsuccessful.
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Stop loading new web resource data, and silently exit.
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!status.is_success() || (response_code != 200))
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->UpdateResourceCache(data);
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    web_resource_service_->Release();
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // So that we can delay our start so as not to affect start-up time; also,
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // so that we can schedule future cache updates.
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedRunnableMethodFactory<WebResourceFetcher> fetcher_factory_;
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tool that fetches the url data from the server.
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<URLFetcher> url_fetcher_;
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Our owner and creator. Ref counted.
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  WebResourceService* web_resource_service_;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class coordinates a web resource unpack and parse task which is run in
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// a separate process.  Results are sent back to this class and routed to
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the WebResourceService.
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebResourceService::UnpackerClient
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public UtilityProcessHost::Client {
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UnpackerClient(WebResourceService* web_resource_service,
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 const std::string& json_data)
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : web_resource_service_(web_resource_service),
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      json_data_(json_data), got_response_(false) {
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Start() {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddRef();  // balanced in Cleanup.
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // TODO(willchan): Look for a better signal of whether we're in a unit test
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // or not. Using |resource_dispatcher_host_| for this is pretty lame.
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we don't have a resource_dispatcher_host_, assume we're in
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // a test and run the unpacker directly in-process.
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool use_utility_process =
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        web_resource_service_->resource_dispatcher_host_ != NULL &&
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (use_utility_process) {
134731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::ID thread_id;
135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_id));
136731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
137731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::IO, FROM_HERE,
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NewRunnableMethod(this, &UnpackerClient::StartProcessOnIOThread,
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            thread_id));
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      WebResourceUnpacker unpacker(json_data_);
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (unpacker.Run()) {
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        OnUnpackWebResourceSucceeded(*unpacker.parsed_json());
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        OnUnpackWebResourceFailed(unpacker.error_message());
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~UnpackerClient() {}
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // UtilityProcessHost::Client
15421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  virtual void OnProcessCrashed(int exit_code) {
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (got_response_)
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnUnpackWebResourceFailed(
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "Chrome crashed while trying to retrieve web resources.");
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnUnpackWebResourceSucceeded(
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const DictionaryValue& parsed_json) {
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->OnWebResourceUnpacked(parsed_json);
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cleanup();
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnUnpackWebResourceFailed(const std::string& error_message) {
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->EndFetch();
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cleanup();
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Release reference and set got_response_.
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Cleanup() {
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (got_response_)
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    got_response_ = true;
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Release();
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void StartProcessOnIOThread(BrowserThread::ID thread_id) {
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    UtilityProcessHost* host = new UtilityProcessHost(this, thread_id);
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(mrc): get proper file path when we start using web resources
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // that need to be unpacked.
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    host->StartWebResourceUnpacker(json_data_);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<WebResourceService> web_resource_service_;
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Holds raw JSON string.
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string& json_data_;
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // True if we got a response from the utility process and have cleaned up
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // already.
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool got_response_;
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
199dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenWebResourceService::WebResourceService(
200dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    Profile* profile,
201dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    PrefService* prefs,
202dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const char* web_resource_server,
203dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    bool apply_locale_to_url,
204dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    NotificationType::Type notification_type,
205dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const char* last_update_time_pref_name,
206dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int start_fetch_delay,
207dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int cache_update_delay)
208dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : prefs_(prefs),
209201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      profile_(profile),
210201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(service_factory_(this)),
211201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      in_fetch_(false),
212dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      web_resource_server_(web_resource_server),
213dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      apply_locale_to_url_(apply_locale_to_url),
214dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      notification_type_(notification_type),
215dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      last_update_time_pref_name_(last_update_time_pref_name),
216dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      start_fetch_delay_(start_fetch_delay),
217dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      cache_update_delay_(cache_update_delay),
218201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      web_resource_update_scheduled_(false) {
219dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(prefs);
220dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(profile);
221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  prefs_->RegisterStringPref(last_update_time_pref_name, "0");
222dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  resource_dispatcher_host_ = g_browser_process->resource_dispatcher_host();
223dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  web_resource_fetcher_.reset(new WebResourceFetcher(this));
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebResourceService::~WebResourceService() { }
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid WebResourceService::PostNotification(int64 delay_ms) {
229dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (web_resource_update_scheduled_)
230dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
231dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (delay_ms > 0) {
232dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    web_resource_update_scheduled_ = true;
233dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    MessageLoop::current()->PostDelayedTask(FROM_HERE,
234dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        service_factory_.NewRunnableMethod(
235dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            &WebResourceService::WebResourceStateChange), delay_ms);
236dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else if (delay_ms == 0) {
237dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    WebResourceStateChange();
238dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::EndFetch() {
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  in_fetch_ = false;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::OnWebResourceUnpacked(
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const DictionaryValue& parsed_json) {
247dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  Unpack(parsed_json);
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EndFetch();
2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
251201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid WebResourceService::WebResourceStateChange() {
252201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  web_resource_update_scheduled_ = false;
253dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (notification_type_ == NotificationType::NOTIFICATION_TYPE_COUNT)
254dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
255201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  NotificationService* service = NotificationService::current();
256dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  service->Notify(notification_type_,
257201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                  Source<WebResourceService>(this),
258201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                  NotificationService::NoDetails());
259201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
260201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WebResourceService::StartAfterDelay() {
262dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  int64 delay = start_fetch_delay_;
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Check whether we have ever put a value in the web resource cache;
2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // if so, pull it out and see if it's time to update again.
265dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (prefs_->HasPrefPath(last_update_time_pref_name_)) {
2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string last_update_pref =
267dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        prefs_->GetString(last_update_time_pref_name_);
2683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!last_update_pref.empty()) {
2693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      double last_update_value;
2703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      base::StringToDouble(last_update_pref, &last_update_value);
27172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      int64 ms_until_update = cache_update_delay_ -
27272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          static_cast<int64>((base::Time::Now() - base::Time::FromDoubleT(
2733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          last_update_value)).InMilliseconds());
274201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      delay = ms_until_update > cache_update_delay_ ?
275dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          cache_update_delay_ : (ms_until_update < start_fetch_delay_ ?
276dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                start_fetch_delay_ : ms_until_update);
2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
2783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Start fetch and wait for UpdateResourceCache.
28072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  web_resource_fetcher_->StartAfterDelay(delay);
2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WebResourceService::UpdateResourceCache(const std::string& json_data) {
2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  UnpackerClient* client = new UnpackerClient(this, json_data);
2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  client->Start();
2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
287201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Set cache update time in preferences.
288dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  prefs_->SetString(last_update_time_pref_name_,
2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      base::DoubleToString(base::Time::Now().ToDoubleT()));
2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
291