Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(383)

Side by Side Diff: chrome/browser/translate/translate_language_list.cc

Issue 15949022: Translate: language list smart updater (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: nits for retry Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/translate/translate_language_list.h" 5 #include "chrome/browser/translate/translate_language_list.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #include "base/bind.h"
9 #include "base/json/json_reader.h" 10 #include "base/json/json_reader.h"
10 #include "base/lazy_instance.h" 11 #include "base/lazy_instance.h"
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "base/string_util.h" 13 #include "base/string_util.h"
13 #include "base/stringprintf.h" 14 #include "base/stringprintf.h"
14 #include "base/values.h" 15 #include "base/values.h"
15 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/translate/translate_event_details.h" 17 #include "chrome/browser/translate/translate_event_details.h"
17 #include "chrome/browser/translate/translate_manager.h" 18 #include "chrome/browser/translate/translate_manager.h"
18 #include "chrome/browser/translate/translate_url_util.h" 19 #include "chrome/browser/translate/translate_url_util.h"
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 // Constant URL string to fetch server supporting language list. 98 // Constant URL string to fetch server supporting language list.
98 const char kLanguageListFetchURL[] = 99 const char kLanguageListFetchURL[] =
99 "https://translate.googleapis.com/translate_a/l?client=chrome&cb=sl"; 100 "https://translate.googleapis.com/translate_a/l?client=chrome&cb=sl";
100 101
101 // Used in kTranslateScriptURL to request supporting languages list including 102 // Used in kTranslateScriptURL to request supporting languages list including
102 // "alpha languages". 103 // "alpha languages".
103 const char kAlphaLanguageQueryName[] = "alpha"; 104 const char kAlphaLanguageQueryName[] = "alpha";
104 const char kAlphaLanguageQueryValue[] = "1"; 105 const char kAlphaLanguageQueryValue[] = "1";
105 106
106 // Retry parameter for fetching supporting language list. 107 // Retry parameter for fetching supporting language list.
107 const int kMaxRetryLanguageListFetch = 5; 108 const int kMaxRetryLanguageListFetchOn5xx = 5;
108 109
110 // Retry parameter for LanguageListFetcher.
111 const int kMaxRetryLanguageListFetch = 16;
112
113 // Assign following IDs to URLFetchers so that tests can distinguish each
114 // request in order to simiulate respectively.
109 const int kFetcherIdForLanguageList = 1; 115 const int kFetcherIdForLanguageList = 1;
110 const int kFetcherIdForAlphaLanguageList = 2; 116 const int kFetcherIdForAlphaLanguageList = 2;
111 117
112 // Show a message in chrome:://translate-internals Event Logs. 118 // Show a message in chrome:://translate-internals Event Logs.
113 void NotifyEvent(int line, const std::string& message) { 119 void NotifyEvent(int line, const std::string& message) {
114 TranslateManager* manager = TranslateManager::GetInstance(); 120 TranslateManager* manager = TranslateManager::GetInstance();
115 DCHECK(manager); 121 DCHECK(manager);
116 122
117 TranslateEventDetails details(__FILE__, line, message); 123 TranslateEventDetails details(__FILE__, line, message);
118 manager->NotifyTranslateEvent(details); 124 manager->NotifyTranslateEvent(details);
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 // TODO(toyoshim): Check if UI libraries support adding locale. 175 // TODO(toyoshim): Check if UI libraries support adding locale.
170 set->insert(iter.key()); 176 set->insert(iter.key());
171 if (message.empty()) 177 if (message.empty())
172 message += iter.key(); 178 message += iter.key();
173 else 179 else
174 message += ", " + iter.key(); 180 message += ", " + iter.key();
175 } 181 }
176 NotifyEvent(__LINE__, message); 182 NotifyEvent(__LINE__, message);
177 } 183 }
178 184
179 // Creates URLFetcher, sets arguments to start, and returns the object. 185 // Check if |n| is 2^n (n >= 0).
180 net::URLFetcher* CreateAndStartFetch(int id, 186 bool IsOneHot(int n) {
MAD 2013/06/10 18:28:10 I would prefer to name this: IsPowerOfTwo. And he
Takashi Toyoshima 2013/06/12 05:20:43 I'll stop to use exponential backoff here. Because
181 const GURL& url, 187 int hot_count = 0;
182 net::URLFetcherDelegate* delegate) { 188 for (int bit = 1; bit != 0; bit <<= 1)
183 DCHECK(delegate); 189 if (n & bit)
184 std::string message = base::StringPrintf( 190 hot_count++;
185 "%s list fetch starts (URL: %s)", 191 return hot_count == 1;
186 (id == kFetcherIdForLanguageList) ? "Language" : "Alpha language",
187 url.spec().c_str());
188 NotifyEvent(__LINE__, message);
189
190 scoped_ptr<net::URLFetcher> fetcher;
191 fetcher.reset(net::URLFetcher::Create(id,
192 url,
193 net::URLFetcher::GET,
194 delegate));
195 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
196 net::LOAD_DO_NOT_SAVE_COOKIES);
197 fetcher->SetRequestContext(g_browser_process->system_request_context());
198 fetcher->SetMaxRetriesOn5xx(kMaxRetryLanguageListFetch);
199 fetcher->Start();
200
201 return fetcher.release();
202 } 192 }
203 193
204 } // namespace 194 } // namespace
205 195
196 TranslateLanguageList::LanguageListFetcher::LanguageListFetcher(
197 bool include_alpha_languages)
198 : include_alpha_languages_(include_alpha_languages),
199 state_(IDLE),
200 retry_count_(0) {
MAD 2013/06/10 18:28:10 You never reset it to 0, so it's not just retries,
Takashi Toyoshima 2013/06/12 05:20:43 If I reset retry_count whenever a request is issue
201 }
202
203 TranslateLanguageList::LanguageListFetcher::~LanguageListFetcher() {
204 }
205
206 bool TranslateLanguageList::LanguageListFetcher::Request(
207 const TranslateLanguageList::LanguageListFetcher::Callback& callback) {
208 // This function is not supporsed to be called before previous operaion is not
MAD 2013/06/10 18:28:10 supporsed -> supposed
Takashi Toyoshima 2013/06/12 05:20:43 Done.
209 // finished.
210 if (state_ == REQUESTING) {
211 NOTREACHED();
212 return false;
213 }
214
215 // Omit requests to realize an exponential backoff'd retries.
216 // Request will be issued when |retry_count_| is 2^n (n >= 0) and it doesn't
217 // reach to limitation.
218 if (retry_count_ >= (1 << kMaxRetryLanguageListFetch)) {
219 NotifyEvent(__LINE__, "Request is omitted due to retry limitation");
220 return false;
221 }
222 if (!IsOneHot(++retry_count_)) {
MAD 2013/06/10 18:28:10 Actually, the URLFetcher already supports backoff
Takashi Toyoshima 2013/06/12 05:20:43 Yes. But it works only against HTTP status 5xx. Th
223 NotifyEvent(__LINE__, "Request is omitted due to exponential backoff");
224 return false;
225 }
226
227 state_ = REQUESTING;
228 callback_ = callback;
229
230 GURL url = GURL(kLanguageListFetchURL);
231 url = TranslateURLUtil::AddHostLocaleToUrl(url);
232 url = TranslateURLUtil::AddApiKeyToUrl(url);
233 if (include_alpha_languages_) {
234 url = net::AppendQueryParameter(url,
235 kAlphaLanguageQueryName,
236 kAlphaLanguageQueryValue);
237 }
238
239 std::string message = base::StringPrintf(
240 "%s list fetch starts (URL: %s)",
241 include_alpha_languages_ ? "Language" : "Alpha language",
242 url.spec().c_str());
243 NotifyEvent(__LINE__, message);
244
245 fetcher_.reset(net::URLFetcher::Create(
246 include_alpha_languages_ ? kFetcherIdForAlphaLanguageList :
247 kFetcherIdForLanguageList,
248 url,
249 net::URLFetcher::GET,
250 this));
251 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
252 net::LOAD_DO_NOT_SAVE_COOKIES);
253 fetcher_->SetRequestContext(g_browser_process->system_request_context());
254 fetcher_->SetMaxRetriesOn5xx(kMaxRetryLanguageListFetchOn5xx);
255 fetcher_->Start();
256
257 return true;
258 }
259
260 void TranslateLanguageList::LanguageListFetcher::OnURLFetchComplete(
261 const net::URLFetcher* source) {
262 DCHECK(fetcher_.get() == source);
263
264 std::string data;
265 if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
266 source->GetResponseCode() == net::HTTP_OK) {
267 state_ = COMPLETED;
268 source->GetResponseAsString(&data);
269 std::string message = base::StringPrintf(
270 "%s list is updated",
271 include_alpha_languages_ ? "Alpha language" : "Language");
272 NotifyEvent(__LINE__, message);
273 } else {
274 state_ = FAILED;
275 std::string message = base::StringPrintf(
276 "Failed to Fetch languages from: %s",
277 source->GetURL().spec().c_str());
278 NotifyEvent(__LINE__, message);
279 }
280
281 scoped_ptr<const net::URLFetcher> delete_ptr(fetcher_.release());
282 callback_.Run(include_alpha_languages_, state_ == COMPLETED, data);
283 }
284
285 // Transfer URLFetcher's ownership before invoking a callback.
206 // This must be kept in sync with the &cb= value in the kLanguageListFetchURL. 286 // This must be kept in sync with the &cb= value in the kLanguageListFetchURL.
207 const char TranslateLanguageList::kLanguageListCallbackName[] = "sl("; 287 const char TranslateLanguageList::kLanguageListCallbackName[] = "sl(";
208 const char TranslateLanguageList::kTargetLanguagesKey[] = "tl"; 288 const char TranslateLanguageList::kTargetLanguagesKey[] = "tl";
209 289
210 TranslateLanguageList::TranslateLanguageList() { 290 TranslateLanguageList::TranslateLanguageList() {
211 // We default to our hard coded list of languages in 291 // We default to our hard coded list of languages in
212 // |kDefaultSupportedLanguages|. This list will be overriden by a server 292 // |kDefaultSupportedLanguages|. This list will be overriden by a server
213 // providing supported langauges list. 293 // providing supported langauges list.
214 for (size_t i = 0; i < arraysize(kDefaultSupportedLanguages); ++i) 294 for (size_t i = 0; i < arraysize(kDefaultSupportedLanguages); ++i)
215 supported_languages_.insert(kDefaultSupportedLanguages[i]); 295 supported_languages_.insert(kDefaultSupportedLanguages[i]);
216 UpdateSupportedLanguages(); 296 UpdateSupportedLanguages();
297
298 language_list_fetcher_.reset(new LanguageListFetcher(false));
299 alpha_language_list_fetcher_.reset(new LanguageListFetcher(true));
300
301 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
217 } 302 }
218 303
219 TranslateLanguageList::~TranslateLanguageList() {} 304 TranslateLanguageList::~TranslateLanguageList() {
220 305 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
221 void TranslateLanguageList::OnURLFetchComplete(const net::URLFetcher* source) {
222 scoped_ptr<const net::URLFetcher> delete_ptr;
223
224 if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
225 source->GetResponseCode() == net::HTTP_OK) {
226 std::string data;
227 source->GetResponseAsString(&data);
228 if (language_list_fetcher_.get() == source) {
229 NotifyEvent(__LINE__, "Language list is updated");
230 delete_ptr.reset(language_list_fetcher_.release());
231 SetSupportedLanguages(data, &supported_languages_);
232 } else if (alpha_language_list_fetcher_.get() == source) {
233 NotifyEvent(__LINE__, "Alpha language list is updated");
234 delete_ptr.reset(alpha_language_list_fetcher_.release());
235 SetSupportedLanguages(data, &supported_alpha_languages_);
236 } else {
237 NOTREACHED();
238 }
239 UpdateSupportedLanguages();
240 } else {
241 // TODO(toyoshim): Try again. http://crbug.com/244202 .
242 // Also In CrOS, FetchLanguageList is not called at launching Chrome. It
243 // will solve this problem that check if FetchLanguageList is already
244 // called, and call it if needed in InitSupportedLanguage().
245 std::string message = base::StringPrintf(
246 "%s list update fails (Status: %d, URL: %s)",
247 (language_list_fetcher_.get() == source) ? "Language" :
248 "Alpha language",
249 source->GetResponseCode(),
250 source->GetOriginalURL().spec().c_str());
251 NotifyEvent(__LINE__, message);
252 }
253 } 306 }
254 307
255 void TranslateLanguageList::GetSupportedLanguages( 308 void TranslateLanguageList::GetSupportedLanguages(
256 std::vector<std::string>* languages) { 309 std::vector<std::string>* languages) {
257 DCHECK(languages && languages->empty()); 310 DCHECK(languages && languages->empty());
258 std::set<std::string>::const_iterator iter = all_supported_languages_.begin(); 311 std::set<std::string>::const_iterator iter = all_supported_languages_.begin();
259 for (; iter != all_supported_languages_.end(); ++iter) 312 for (; iter != all_supported_languages_.end(); ++iter)
260 languages->push_back(*iter); 313 languages->push_back(*iter);
314
315 // Update language lists if they are not updated after Chrome was launched
316 // for later requests.
317 RequestLanguageList();
261 } 318 }
262 319
263 std::string TranslateLanguageList::GetLanguageCode( 320 std::string TranslateLanguageList::GetLanguageCode(
264 const std::string& chrome_locale) { 321 const std::string& chrome_locale) {
265 // Only remove the country code for country specific languages we don't 322 // Only remove the country code for country specific languages we don't
266 // support specifically yet. 323 // support specifically yet.
267 if (IsSupportedLanguage(chrome_locale)) 324 if (IsSupportedLanguage(chrome_locale))
268 return chrome_locale; 325 return chrome_locale;
269 326
270 size_t hypen_index = chrome_locale.find('-'); 327 size_t hypen_index = chrome_locale.find('-');
271 if (hypen_index == std::string::npos) 328 if (hypen_index == std::string::npos)
272 return chrome_locale; 329 return chrome_locale;
273 return chrome_locale.substr(0, hypen_index); 330 return chrome_locale.substr(0, hypen_index);
274 } 331 }
275 332
276 bool TranslateLanguageList::IsSupportedLanguage(const std::string& language) { 333 bool TranslateLanguageList::IsSupportedLanguage(const std::string& language) {
277 return all_supported_languages_.count(language) != 0; 334 return all_supported_languages_.count(language) != 0;
278 } 335 }
279 336
280 bool TranslateLanguageList::IsAlphaLanguage(const std::string& language) { 337 bool TranslateLanguageList::IsAlphaLanguage(const std::string& language) {
281 // |language| should exist only in the alpha language list. 338 // |language| should exist only in the alpha language list.
282 return supported_alpha_languages_.count(language) != 0 && 339 return supported_alpha_languages_.count(language) != 0 &&
283 supported_languages_.count(language) == 0; 340 supported_languages_.count(language) == 0;
284 } 341 }
285 342
286 void TranslateLanguageList::RequestLanguageList() { 343 void TranslateLanguageList::RequestLanguageList() {
287 if (language_list_fetcher_.get() || alpha_language_list_fetcher_.get()) 344 if (language_list_fetcher_.get() &&
345 (language_list_fetcher_->state() == LanguageListFetcher::IDLE ||
346 language_list_fetcher_->state() == LanguageListFetcher::FAILED)) {
347 language_list_fetcher_->Request(
348 base::Bind(&TranslateLanguageList::OnLanguageListFetchComplete,
349 base::Unretained(this)));
350 }
351
352 if (alpha_language_list_fetcher_.get() &&
353 (alpha_language_list_fetcher_->state() == LanguageListFetcher::IDLE ||
354 alpha_language_list_fetcher_->state() == LanguageListFetcher::FAILED)) {
355 alpha_language_list_fetcher_->Request(
356 base::Bind(&TranslateLanguageList::OnLanguageListFetchComplete,
357 base::Unretained(this)));
358 }
359 }
360
361 void TranslateLanguageList::OnNetworkChanged(
362 net::NetworkChangeNotifier::ConnectionType type) {
363 std::string message = base::StringPrintf("OnNetworkChanged: %d, %s", type,
364 net::NetworkChangeNotifier::IsOffline() ? "offline" : "online");
365 NotifyEvent(__LINE__, message);
366
367 if (net::NetworkChangeNotifier::IsOffline())
288 return; 368 return;
289 369
290 // Fetch the stable language list. 370 RequestLanguageList();
291 GURL language_list_fetch_url = GURL(kLanguageListFetchURL); 371 }
292 language_list_fetch_url =
293 TranslateURLUtil::AddHostLocaleToUrl(language_list_fetch_url);
294 language_list_fetch_url =
295 TranslateURLUtil::AddApiKeyToUrl(language_list_fetch_url);
296 372
297 language_list_fetcher_.reset( 373 void TranslateLanguageList::OnLanguageListFetchComplete(
298 CreateAndStartFetch(kFetcherIdForLanguageList, 374 bool include_alpha_languages,
299 language_list_fetch_url, 375 bool success,
300 this)); 376 const std::string& data) {
377 if (!success)
MAD 2013/06/10 18:28:10 You don't actually retry on failures, and you don'
Takashi Toyoshima 2013/06/12 05:20:43 No. It was invoked in GetSupportedLanguages() if t
378 return;
301 379
302 // Fetch the alpha language list. 380 if (!include_alpha_languages) {
303 language_list_fetch_url = net::AppendQueryParameter( 381 SetSupportedLanguages(data, &supported_languages_);
304 language_list_fetch_url, 382 language_list_fetcher_.reset();
305 kAlphaLanguageQueryName, 383 } else {
306 kAlphaLanguageQueryValue); 384 SetSupportedLanguages(data, &supported_alpha_languages_);
307 385 alpha_language_list_fetcher_.reset();
308 alpha_language_list_fetcher_.reset( 386 }
309 CreateAndStartFetch(kFetcherIdForAlphaLanguageList, 387 UpdateSupportedLanguages();
310 language_list_fetch_url,
311 this));
312 } 388 }
313 389
314 void TranslateLanguageList::UpdateSupportedLanguages() { 390 void TranslateLanguageList::UpdateSupportedLanguages() {
315 all_supported_languages_.clear(); 391 all_supported_languages_.clear();
316 std::set<std::string>::const_iterator iter; 392 std::set<std::string>::const_iterator iter;
317 for (iter = supported_languages_.begin(); 393 for (iter = supported_languages_.begin();
318 iter != supported_languages_.end(); 394 iter != supported_languages_.end();
319 ++iter) 395 ++iter)
320 all_supported_languages_.insert(*iter); 396 all_supported_languages_.insert(*iter);
321 for (iter = supported_alpha_languages_.begin(); 397 for (iter = supported_alpha_languages_.begin();
322 iter != supported_alpha_languages_.end(); 398 iter != supported_alpha_languages_.end();
323 ++iter) 399 ++iter)
324 all_supported_languages_.insert(*iter); 400 all_supported_languages_.insert(*iter);
325 } 401 }
OLDNEW
« no previous file with comments | « chrome/browser/translate/translate_language_list.h ('k') | chrome/browser/translate/translate_manager_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698