Chromium Code Reviews| Index: chrome/browser/translate/translate_language_list.cc |
| diff --git a/chrome/browser/translate/translate_language_list.cc b/chrome/browser/translate/translate_language_list.cc |
| index 597ca46b80d185c2ecfebead8b25b740e8519463..5e4404bb59f5dad5208fdb4ed9e912071ac7f5ae 100644 |
| --- a/chrome/browser/translate/translate_language_list.cc |
| +++ b/chrome/browser/translate/translate_language_list.cc |
| @@ -6,6 +6,7 @@ |
| #include <set> |
| +#include "base/bind.h" |
| #include "base/json/json_reader.h" |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| @@ -104,8 +105,13 @@ const char kAlphaLanguageQueryName[] = "alpha"; |
| const char kAlphaLanguageQueryValue[] = "1"; |
| // Retry parameter for fetching supporting language list. |
| -const int kMaxRetryLanguageListFetch = 5; |
| +const int kMaxRetryLanguageListFetchOn5xx = 5; |
| +// Retry parameter for LanguageListFetcher. |
| +const int kMaxRetryLanguageListFetch = 16; |
| + |
| +// Assign following IDs to URLFetchers so that tests can distinguish each |
| +// request in order to simiulate respectively. |
| const int kFetcherIdForLanguageList = 1; |
| const int kFetcherIdForAlphaLanguageList = 2; |
| @@ -176,33 +182,107 @@ void SetSupportedLanguages(const std::string& language_list, |
| NotifyEvent(__LINE__, message); |
| } |
| -// Creates URLFetcher, sets arguments to start, and returns the object. |
| -net::URLFetcher* CreateAndStartFetch(int id, |
| - const GURL& url, |
| - net::URLFetcherDelegate* delegate) { |
| - DCHECK(delegate); |
| +// Check if |n| is 2^n (n >= 0). |
| +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
|
| + int hot_count = 0; |
| + for (int bit = 1; bit != 0; bit <<= 1) |
| + if (n & bit) |
| + hot_count++; |
| + return hot_count == 1; |
| +} |
| + |
| +} // namespace |
| + |
| +TranslateLanguageList::LanguageListFetcher::LanguageListFetcher( |
| + bool include_alpha_languages) |
| + : include_alpha_languages_(include_alpha_languages), |
| + state_(IDLE), |
| + 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
|
| +} |
| + |
| +TranslateLanguageList::LanguageListFetcher::~LanguageListFetcher() { |
| +} |
| + |
| +bool TranslateLanguageList::LanguageListFetcher::Request( |
| + const TranslateLanguageList::LanguageListFetcher::Callback& callback) { |
| + // 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.
|
| + // finished. |
| + if (state_ == REQUESTING) { |
| + NOTREACHED(); |
| + return false; |
| + } |
| + |
| + // Omit requests to realize an exponential backoff'd retries. |
| + // Request will be issued when |retry_count_| is 2^n (n >= 0) and it doesn't |
| + // reach to limitation. |
| + if (retry_count_ >= (1 << kMaxRetryLanguageListFetch)) { |
| + NotifyEvent(__LINE__, "Request is omitted due to retry limitation"); |
| + return false; |
| + } |
| + 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
|
| + NotifyEvent(__LINE__, "Request is omitted due to exponential backoff"); |
| + return false; |
| + } |
| + |
| + state_ = REQUESTING; |
| + callback_ = callback; |
| + |
| + GURL url = GURL(kLanguageListFetchURL); |
| + url = TranslateURLUtil::AddHostLocaleToUrl(url); |
| + url = TranslateURLUtil::AddApiKeyToUrl(url); |
| + if (include_alpha_languages_) { |
| + url = net::AppendQueryParameter(url, |
| + kAlphaLanguageQueryName, |
| + kAlphaLanguageQueryValue); |
| + } |
| + |
| std::string message = base::StringPrintf( |
| "%s list fetch starts (URL: %s)", |
| - (id == kFetcherIdForLanguageList) ? "Language" : "Alpha language", |
| + include_alpha_languages_ ? "Language" : "Alpha language", |
| url.spec().c_str()); |
| NotifyEvent(__LINE__, message); |
| - scoped_ptr<net::URLFetcher> fetcher; |
| - fetcher.reset(net::URLFetcher::Create(id, |
| - url, |
| - net::URLFetcher::GET, |
| - delegate)); |
| - fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| - net::LOAD_DO_NOT_SAVE_COOKIES); |
| - fetcher->SetRequestContext(g_browser_process->system_request_context()); |
| - fetcher->SetMaxRetriesOn5xx(kMaxRetryLanguageListFetch); |
| - fetcher->Start(); |
| - |
| - return fetcher.release(); |
| + fetcher_.reset(net::URLFetcher::Create( |
| + include_alpha_languages_ ? kFetcherIdForAlphaLanguageList : |
| + kFetcherIdForLanguageList, |
| + url, |
| + net::URLFetcher::GET, |
| + this)); |
| + fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| + net::LOAD_DO_NOT_SAVE_COOKIES); |
| + fetcher_->SetRequestContext(g_browser_process->system_request_context()); |
| + fetcher_->SetMaxRetriesOn5xx(kMaxRetryLanguageListFetchOn5xx); |
| + fetcher_->Start(); |
| + |
| + return true; |
| } |
| -} // namespace |
| +void TranslateLanguageList::LanguageListFetcher::OnURLFetchComplete( |
| + const net::URLFetcher* source) { |
| + DCHECK(fetcher_.get() == source); |
| + std::string data; |
| + if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS && |
| + source->GetResponseCode() == net::HTTP_OK) { |
| + state_ = COMPLETED; |
| + source->GetResponseAsString(&data); |
| + std::string message = base::StringPrintf( |
| + "%s list is updated", |
| + include_alpha_languages_ ? "Alpha language" : "Language"); |
| + NotifyEvent(__LINE__, message); |
| + } else { |
| + state_ = FAILED; |
| + std::string message = base::StringPrintf( |
| + "Failed to Fetch languages from: %s", |
| + source->GetURL().spec().c_str()); |
| + NotifyEvent(__LINE__, message); |
| + } |
| + |
| + scoped_ptr<const net::URLFetcher> delete_ptr(fetcher_.release()); |
| + callback_.Run(include_alpha_languages_, state_ == COMPLETED, data); |
| +} |
| + |
| +// Transfer URLFetcher's ownership before invoking a callback. |
| // This must be kept in sync with the &cb= value in the kLanguageListFetchURL. |
| const char TranslateLanguageList::kLanguageListCallbackName[] = "sl("; |
| const char TranslateLanguageList::kTargetLanguagesKey[] = "tl"; |
| @@ -214,42 +294,15 @@ TranslateLanguageList::TranslateLanguageList() { |
| for (size_t i = 0; i < arraysize(kDefaultSupportedLanguages); ++i) |
| supported_languages_.insert(kDefaultSupportedLanguages[i]); |
| UpdateSupportedLanguages(); |
| -} |
| -TranslateLanguageList::~TranslateLanguageList() {} |
| + language_list_fetcher_.reset(new LanguageListFetcher(false)); |
| + alpha_language_list_fetcher_.reset(new LanguageListFetcher(true)); |
| -void TranslateLanguageList::OnURLFetchComplete(const net::URLFetcher* source) { |
| - scoped_ptr<const net::URLFetcher> delete_ptr; |
| + net::NetworkChangeNotifier::AddNetworkChangeObserver(this); |
| +} |
| - if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS && |
| - source->GetResponseCode() == net::HTTP_OK) { |
| - std::string data; |
| - source->GetResponseAsString(&data); |
| - if (language_list_fetcher_.get() == source) { |
| - NotifyEvent(__LINE__, "Language list is updated"); |
| - delete_ptr.reset(language_list_fetcher_.release()); |
| - SetSupportedLanguages(data, &supported_languages_); |
| - } else if (alpha_language_list_fetcher_.get() == source) { |
| - NotifyEvent(__LINE__, "Alpha language list is updated"); |
| - delete_ptr.reset(alpha_language_list_fetcher_.release()); |
| - SetSupportedLanguages(data, &supported_alpha_languages_); |
| - } else { |
| - NOTREACHED(); |
| - } |
| - UpdateSupportedLanguages(); |
| - } else { |
| - // TODO(toyoshim): Try again. http://crbug.com/244202 . |
| - // Also In CrOS, FetchLanguageList is not called at launching Chrome. It |
| - // will solve this problem that check if FetchLanguageList is already |
| - // called, and call it if needed in InitSupportedLanguage(). |
| - std::string message = base::StringPrintf( |
| - "%s list update fails (Status: %d, URL: %s)", |
| - (language_list_fetcher_.get() == source) ? "Language" : |
| - "Alpha language", |
| - source->GetResponseCode(), |
| - source->GetOriginalURL().spec().c_str()); |
| - NotifyEvent(__LINE__, message); |
| - } |
| +TranslateLanguageList::~TranslateLanguageList() { |
| + net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); |
| } |
| void TranslateLanguageList::GetSupportedLanguages( |
| @@ -258,6 +311,10 @@ void TranslateLanguageList::GetSupportedLanguages( |
| std::set<std::string>::const_iterator iter = all_supported_languages_.begin(); |
| for (; iter != all_supported_languages_.end(); ++iter) |
| languages->push_back(*iter); |
| + |
| + // Update language lists if they are not updated after Chrome was launched |
| + // for later requests. |
| + RequestLanguageList(); |
| } |
| std::string TranslateLanguageList::GetLanguageCode( |
| @@ -284,31 +341,50 @@ bool TranslateLanguageList::IsAlphaLanguage(const std::string& language) { |
| } |
| void TranslateLanguageList::RequestLanguageList() { |
| - if (language_list_fetcher_.get() || alpha_language_list_fetcher_.get()) |
| + if (language_list_fetcher_.get() && |
| + (language_list_fetcher_->state() == LanguageListFetcher::IDLE || |
| + language_list_fetcher_->state() == LanguageListFetcher::FAILED)) { |
| + language_list_fetcher_->Request( |
| + base::Bind(&TranslateLanguageList::OnLanguageListFetchComplete, |
| + base::Unretained(this))); |
| + } |
| + |
| + if (alpha_language_list_fetcher_.get() && |
| + (alpha_language_list_fetcher_->state() == LanguageListFetcher::IDLE || |
| + alpha_language_list_fetcher_->state() == LanguageListFetcher::FAILED)) { |
| + alpha_language_list_fetcher_->Request( |
| + base::Bind(&TranslateLanguageList::OnLanguageListFetchComplete, |
| + base::Unretained(this))); |
| + } |
| +} |
| + |
| +void TranslateLanguageList::OnNetworkChanged( |
| + net::NetworkChangeNotifier::ConnectionType type) { |
| + std::string message = base::StringPrintf("OnNetworkChanged: %d, %s", type, |
| + net::NetworkChangeNotifier::IsOffline() ? "offline" : "online"); |
| + NotifyEvent(__LINE__, message); |
| + |
| + if (net::NetworkChangeNotifier::IsOffline()) |
| return; |
| - // Fetch the stable language list. |
| - GURL language_list_fetch_url = GURL(kLanguageListFetchURL); |
| - language_list_fetch_url = |
| - TranslateURLUtil::AddHostLocaleToUrl(language_list_fetch_url); |
| - language_list_fetch_url = |
| - TranslateURLUtil::AddApiKeyToUrl(language_list_fetch_url); |
| - |
| - language_list_fetcher_.reset( |
| - CreateAndStartFetch(kFetcherIdForLanguageList, |
| - language_list_fetch_url, |
| - this)); |
| - |
| - // Fetch the alpha language list. |
| - language_list_fetch_url = net::AppendQueryParameter( |
| - language_list_fetch_url, |
| - kAlphaLanguageQueryName, |
| - kAlphaLanguageQueryValue); |
| - |
| - alpha_language_list_fetcher_.reset( |
| - CreateAndStartFetch(kFetcherIdForAlphaLanguageList, |
| - language_list_fetch_url, |
| - this)); |
| + RequestLanguageList(); |
| +} |
| + |
| +void TranslateLanguageList::OnLanguageListFetchComplete( |
| + bool include_alpha_languages, |
| + bool success, |
| + const std::string& data) { |
| + 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
|
| + return; |
| + |
| + if (!include_alpha_languages) { |
| + SetSupportedLanguages(data, &supported_languages_); |
| + language_list_fetcher_.reset(); |
| + } else { |
| + SetSupportedLanguages(data, &supported_alpha_languages_); |
| + alpha_language_list_fetcher_.reset(); |
| + } |
| + UpdateSupportedLanguages(); |
| } |
| void TranslateLanguageList::UpdateSupportedLanguages() { |