// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/web_resource/web_resource_service.h" #include "base/bind.h" #include "base/message_loop/message_loop.h" #include "base/prefs/pref_service.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/values.h" #include "chrome/browser/browser_process.h" #include "components/google/core/browser/google_util.h" #include "net/base/load_flags.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_request_status.h" #include "url/gurl.h" WebResourceService::WebResourceService( PrefService* prefs, const GURL& web_resource_server, bool apply_locale_to_url, const char* last_update_time_pref_name, int start_fetch_delay_ms, int cache_update_delay_ms) : prefs_(prefs), json_unpacker_(NULL), in_fetch_(false), web_resource_server_(web_resource_server), apply_locale_to_url_(apply_locale_to_url), last_update_time_pref_name_(last_update_time_pref_name), start_fetch_delay_ms_(start_fetch_delay_ms), cache_update_delay_ms_(cache_update_delay_ms), weak_ptr_factory_(this) { resource_request_allowed_notifier_.Init(this); DCHECK(prefs); } WebResourceService::~WebResourceService() { if (in_fetch_) EndFetch(); } void WebResourceService::OnUnpackFinished( const base::DictionaryValue& parsed_json) { Unpack(parsed_json); EndFetch(); } void WebResourceService::OnUnpackError(const std::string& error_message) { LOG(ERROR) << error_message; EndFetch(); } void WebResourceService::EndFetch() { if (json_unpacker_) { json_unpacker_->ClearDelegate(); json_unpacker_ = NULL; } in_fetch_ = false; } void WebResourceService::StartAfterDelay() { // If resource requests are not allowed, we'll get a callback when they are. if (resource_request_allowed_notifier_.ResourceRequestsAllowed()) OnResourceRequestsAllowed(); } void WebResourceService::OnResourceRequestsAllowed() { int64 delay = start_fetch_delay_ms_; // Check whether we have ever put a value in the web resource cache; // if so, pull it out and see if it's time to update again. if (prefs_->HasPrefPath(last_update_time_pref_name_)) { std::string last_update_pref = prefs_->GetString(last_update_time_pref_name_); if (!last_update_pref.empty()) { double last_update_value; base::StringToDouble(last_update_pref, &last_update_value); int64 ms_until_update = cache_update_delay_ms_ - static_cast((base::Time::Now() - base::Time::FromDoubleT( last_update_value)).InMilliseconds()); // Wait at least |start_fetch_delay_ms_|. if (ms_until_update > start_fetch_delay_ms_) delay = ms_until_update; } } // Start fetch and wait for UpdateResourceCache. ScheduleFetch(delay); } // Delay initial load of resource data into cache so as not to interfere // with startup time. void WebResourceService::ScheduleFetch(int64 delay_ms) { base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&WebResourceService::StartFetch, weak_ptr_factory_.GetWeakPtr()), base::TimeDelta::FromMilliseconds(delay_ms)); } // Initializes the fetching of data from the resource server. Data // load calls OnURLFetchComplete. void WebResourceService::StartFetch() { // First, put our next cache load on the MessageLoop. ScheduleFetch(cache_update_delay_ms_); // Set cache update time in preferences. prefs_->SetString(last_update_time_pref_name_, base::DoubleToString(base::Time::Now().ToDoubleT())); // If we are still fetching data, exit. if (in_fetch_) return; in_fetch_ = true; // Balanced in OnURLFetchComplete. AddRef(); GURL web_resource_server = apply_locale_to_url_ ? google_util::AppendGoogleLocaleParam( web_resource_server_, g_browser_process->GetApplicationLocale()) : web_resource_server_; DVLOG(1) << "WebResourceService StartFetch " << web_resource_server; url_fetcher_.reset(net::URLFetcher::Create( web_resource_server, net::URLFetcher::GET, this)); // Do not let url fetcher affect existing state in system context // (by setting cookies, for example). url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); net::URLRequestContextGetter* url_request_context_getter = g_browser_process->system_request_context(); url_fetcher_->SetRequestContext(url_request_context_getter); url_fetcher_->Start(); } void WebResourceService::OnURLFetchComplete(const net::URLFetcher* source) { // Delete the URLFetcher when this function exits. scoped_ptr clean_up_fetcher(url_fetcher_.release()); if (source->GetStatus().is_success() && source->GetResponseCode() == 200) { std::string data; source->GetResponseAsString(&data); // UnpackerClient calls EndFetch and releases itself on completion. json_unpacker_ = JSONAsynchronousUnpacker::Create(this); json_unpacker_->Start(data); } else { // Don't parse data if attempt to download was unsuccessful. // Stop loading new web resource data, and silently exit. // We do not call UnpackerClient, so we need to call EndFetch ourselves. EndFetch(); } Release(); }