1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/web_resource/web_resource_service.h" 6 7 #include "base/bind.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/prefs/pref_service.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_util.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/time/time.h" 14 #include "base/values.h" 15 #include "chrome/browser/browser_process.h" 16 #include "components/google/core/browser/google_util.h" 17 #include "net/base/load_flags.h" 18 #include "net/url_request/url_fetcher.h" 19 #include "net/url_request/url_request_status.h" 20 #include "url/gurl.h" 21 22 WebResourceService::WebResourceService( 23 PrefService* prefs, 24 const GURL& web_resource_server, 25 bool apply_locale_to_url, 26 const char* last_update_time_pref_name, 27 int start_fetch_delay_ms, 28 int cache_update_delay_ms) 29 : prefs_(prefs), 30 json_unpacker_(NULL), 31 in_fetch_(false), 32 web_resource_server_(web_resource_server), 33 apply_locale_to_url_(apply_locale_to_url), 34 last_update_time_pref_name_(last_update_time_pref_name), 35 start_fetch_delay_ms_(start_fetch_delay_ms), 36 cache_update_delay_ms_(cache_update_delay_ms), 37 weak_ptr_factory_(this) { 38 resource_request_allowed_notifier_.Init(this); 39 DCHECK(prefs); 40 } 41 42 WebResourceService::~WebResourceService() { 43 if (in_fetch_) 44 EndFetch(); 45 } 46 47 void WebResourceService::OnUnpackFinished( 48 const base::DictionaryValue& parsed_json) { 49 Unpack(parsed_json); 50 EndFetch(); 51 } 52 53 void WebResourceService::OnUnpackError(const std::string& error_message) { 54 LOG(ERROR) << error_message; 55 EndFetch(); 56 } 57 58 void WebResourceService::EndFetch() { 59 if (json_unpacker_) { 60 json_unpacker_->ClearDelegate(); 61 json_unpacker_ = NULL; 62 } 63 in_fetch_ = false; 64 } 65 66 void WebResourceService::StartAfterDelay() { 67 // If resource requests are not allowed, we'll get a callback when they are. 68 if (resource_request_allowed_notifier_.ResourceRequestsAllowed()) 69 OnResourceRequestsAllowed(); 70 } 71 72 void WebResourceService::OnResourceRequestsAllowed() { 73 int64 delay = start_fetch_delay_ms_; 74 // Check whether we have ever put a value in the web resource cache; 75 // if so, pull it out and see if it's time to update again. 76 if (prefs_->HasPrefPath(last_update_time_pref_name_)) { 77 std::string last_update_pref = 78 prefs_->GetString(last_update_time_pref_name_); 79 if (!last_update_pref.empty()) { 80 double last_update_value; 81 base::StringToDouble(last_update_pref, &last_update_value); 82 int64 ms_until_update = cache_update_delay_ms_ - 83 static_cast<int64>((base::Time::Now() - base::Time::FromDoubleT( 84 last_update_value)).InMilliseconds()); 85 // Wait at least |start_fetch_delay_ms_|. 86 if (ms_until_update > start_fetch_delay_ms_) 87 delay = ms_until_update; 88 } 89 } 90 // Start fetch and wait for UpdateResourceCache. 91 ScheduleFetch(delay); 92 } 93 94 // Delay initial load of resource data into cache so as not to interfere 95 // with startup time. 96 void WebResourceService::ScheduleFetch(int64 delay_ms) { 97 base::MessageLoop::current()->PostDelayedTask( 98 FROM_HERE, 99 base::Bind(&WebResourceService::StartFetch, 100 weak_ptr_factory_.GetWeakPtr()), 101 base::TimeDelta::FromMilliseconds(delay_ms)); 102 } 103 104 // Initializes the fetching of data from the resource server. Data 105 // load calls OnURLFetchComplete. 106 void WebResourceService::StartFetch() { 107 // First, put our next cache load on the MessageLoop. 108 ScheduleFetch(cache_update_delay_ms_); 109 110 // Set cache update time in preferences. 111 prefs_->SetString(last_update_time_pref_name_, 112 base::DoubleToString(base::Time::Now().ToDoubleT())); 113 114 // If we are still fetching data, exit. 115 if (in_fetch_) 116 return; 117 in_fetch_ = true; 118 119 // Balanced in OnURLFetchComplete. 120 AddRef(); 121 122 GURL web_resource_server = 123 apply_locale_to_url_ 124 ? google_util::AppendGoogleLocaleParam( 125 web_resource_server_, g_browser_process->GetApplicationLocale()) 126 : web_resource_server_; 127 128 DVLOG(1) << "WebResourceService StartFetch " << web_resource_server; 129 url_fetcher_.reset(net::URLFetcher::Create( 130 web_resource_server, net::URLFetcher::GET, this)); 131 // Do not let url fetcher affect existing state in system context 132 // (by setting cookies, for example). 133 url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE | 134 net::LOAD_DO_NOT_SEND_COOKIES | 135 net::LOAD_DO_NOT_SAVE_COOKIES); 136 net::URLRequestContextGetter* url_request_context_getter = 137 g_browser_process->system_request_context(); 138 url_fetcher_->SetRequestContext(url_request_context_getter); 139 url_fetcher_->Start(); 140 } 141 142 void WebResourceService::OnURLFetchComplete(const net::URLFetcher* source) { 143 // Delete the URLFetcher when this function exits. 144 scoped_ptr<net::URLFetcher> clean_up_fetcher(url_fetcher_.release()); 145 146 if (source->GetStatus().is_success() && source->GetResponseCode() == 200) { 147 std::string data; 148 source->GetResponseAsString(&data); 149 150 // UnpackerClient calls EndFetch and releases itself on completion. 151 json_unpacker_ = JSONAsynchronousUnpacker::Create(this); 152 json_unpacker_->Start(data); 153 } else { 154 // Don't parse data if attempt to download was unsuccessful. 155 // Stop loading new web resource data, and silently exit. 156 // We do not call UnpackerClient, so we need to call EndFetch ourselves. 157 EndFetch(); 158 } 159 160 Release(); 161 } 162