1 // Copyright 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.
5 #include "components/web_resource/web_resource_service.h"
8 #include "base/location.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/time/time.h"
16 #include "base/values.h"
17 #include "components/google/core/browser/google_util.h"
18 #include "net/base/load_flags.h"
19 #include "net/url_request/url_fetcher.h"
20 #include "net/url_request/url_request_context_getter.h"
21 #include "net/url_request/url_request_status.h"
24 // No anonymous namespace, because const variables automatically get internal
26 const char kInvalidDataTypeError
[] =
27 "Data from web resource server is missing or not valid JSON.";
29 const char kUnexpectedJSONFormatError
[] =
30 "Data from web resource server does not have expected format.";
32 namespace web_resource
{
34 WebResourceService::WebResourceService(
36 const GURL
& web_resource_server
,
37 const std::string
& application_locale
,
38 const char* last_update_time_pref_name
,
39 int start_fetch_delay_ms
,
40 int cache_update_delay_ms
,
41 net::URLRequestContextGetter
* request_context
,
42 const char* disable_network_switch
)
44 resource_request_allowed_notifier_(prefs
, disable_network_switch
),
46 web_resource_server_(web_resource_server
),
47 application_locale_(application_locale
),
48 last_update_time_pref_name_(last_update_time_pref_name
),
49 start_fetch_delay_ms_(start_fetch_delay_ms
),
50 cache_update_delay_ms_(cache_update_delay_ms
),
51 request_context_(request_context
),
52 weak_ptr_factory_(this) {
53 resource_request_allowed_notifier_
.Init(this);
57 void WebResourceService::StartAfterDelay() {
58 // If resource requests are not allowed, we'll get a callback when they are.
59 if (resource_request_allowed_notifier_
.ResourceRequestsAllowed())
60 OnResourceRequestsAllowed();
63 WebResourceService::~WebResourceService() {
66 void WebResourceService::OnURLFetchComplete(const net::URLFetcher
* source
) {
67 // Delete the URLFetcher when this function exits.
68 scoped_ptr
<net::URLFetcher
> clean_up_fetcher(url_fetcher_
.release());
70 if (source
->GetStatus().is_success() && source
->GetResponseCode() == 200) {
72 source
->GetResponseAsString(&data
);
73 // Calls EndFetch() on completion.
74 // Full JSON parsing might spawn a utility process (for security).
75 // To limit the the number of simultaneously active processes
76 // (on Android in particular) we short-cut the full parsing in the case of
77 // trivially "empty" JSONs.
78 if (data
.empty() || data
== "{}") {
79 OnUnpackFinished(make_scoped_ptr(new base::DictionaryValue()).Pass());
81 ParseJSON(data
, base::Bind(&WebResourceService::OnUnpackFinished
,
82 weak_ptr_factory_
.GetWeakPtr()),
83 base::Bind(&WebResourceService::OnUnpackError
,
84 weak_ptr_factory_
.GetWeakPtr()));
87 // Don't parse data if attempt to download was unsuccessful.
88 // Stop loading new web resource data, and silently exit.
89 // We do not call ParseJSON(), so we need to call EndFetch() ourselves.
94 // Delay initial load of resource data into cache so as not to interfere
96 void WebResourceService::ScheduleFetch(int64 delay_ms
) {
97 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
98 FROM_HERE
, base::Bind(&WebResourceService::StartFetch
,
99 weak_ptr_factory_
.GetWeakPtr()),
100 base::TimeDelta::FromMilliseconds(delay_ms
));
103 // Initializes the fetching of data from the resource server. Data
104 // load calls OnURLFetchComplete.
105 void WebResourceService::StartFetch() {
106 // First, put our next cache load on the MessageLoop.
107 ScheduleFetch(cache_update_delay_ms_
);
109 // Set cache update time in preferences.
110 prefs_
->SetString(last_update_time_pref_name_
,
111 base::DoubleToString(base::Time::Now().ToDoubleT()));
113 // If we are still fetching data, exit.
118 GURL web_resource_server
=
119 application_locale_
.empty()
120 ? web_resource_server_
121 : google_util::AppendGoogleLocaleParam(web_resource_server_
,
122 application_locale_
);
124 DVLOG(1) << "WebResourceService StartFetch " << web_resource_server
;
126 net::URLFetcher::Create(web_resource_server
, net::URLFetcher::GET
, this);
127 // Do not let url fetcher affect existing state in system context
128 // (by setting cookies, for example).
129 url_fetcher_
->SetLoadFlags(net::LOAD_DISABLE_CACHE
|
130 net::LOAD_DO_NOT_SEND_COOKIES
|
131 net::LOAD_DO_NOT_SAVE_COOKIES
);
132 url_fetcher_
->SetRequestContext(request_context_
.get());
133 url_fetcher_
->Start();
136 void WebResourceService::EndFetch() {
140 void WebResourceService::OnUnpackFinished(scoped_ptr
<base::Value
> value
) {
142 // Page information not properly read, or corrupted.
143 OnUnpackError(kInvalidDataTypeError
);
146 const base::DictionaryValue
* dict
= nullptr;
147 if (!value
->GetAsDictionary(&dict
)) {
148 OnUnpackError(kUnexpectedJSONFormatError
);
156 void WebResourceService::OnUnpackError(const std::string
& error_message
) {
157 LOG(ERROR
) << error_message
;
161 void WebResourceService::OnResourceRequestsAllowed() {
162 int64 delay
= start_fetch_delay_ms_
;
163 // Check whether we have ever put a value in the web resource cache;
164 // if so, pull it out and see if it's time to update again.
165 if (prefs_
->HasPrefPath(last_update_time_pref_name_
)) {
166 std::string last_update_pref
=
167 prefs_
->GetString(last_update_time_pref_name_
);
168 if (!last_update_pref
.empty()) {
169 double last_update_value
;
170 base::StringToDouble(last_update_pref
, &last_update_value
);
171 int64 ms_until_update
=
172 cache_update_delay_ms_
-
174 (base::Time::Now() - base::Time::FromDoubleT(last_update_value
))
176 // Wait at least |start_fetch_delay_ms_|.
177 if (ms_until_update
> start_fetch_delay_ms_
)
178 delay
= ms_until_update
;
181 // Start fetch and wait for UpdateResourceCache.
182 ScheduleFetch(delay
);
185 } // namespace web_resource