Index: chrome/browser/extensions/app_notify_channel_setup.cc |
diff --git a/chrome/browser/extensions/app_notify_channel_setup.cc b/chrome/browser/extensions/app_notify_channel_setup.cc |
deleted file mode 100644 |
index 8e8dbd11cad43fd68c29f6aa57064e5e32a49765..0000000000000000000000000000000000000000 |
--- a/chrome/browser/extensions/app_notify_channel_setup.cc |
+++ /dev/null |
@@ -1,416 +0,0 @@ |
-// 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/extensions/app_notify_channel_setup.h" |
- |
-#include <string> |
-#include <vector> |
- |
-#include "base/basictypes.h" |
-#include "base/bind.h" |
-#include "base/command_line.h" |
-#include "base/json/json_reader.h" |
-#include "base/message_loop.h" |
-#include "base/metrics/histogram.h" |
-#include "base/prefs/pref_service.h" |
-#include "base/stringprintf.h" |
-#include "chrome/browser/profiles/profile.h" |
-#include "chrome/browser/signin/signin_manager.h" |
-#include "chrome/browser/signin/signin_manager_factory.h" |
-#include "chrome/browser/signin/token_service.h" |
-#include "chrome/browser/signin/token_service_factory.h" |
-#include "chrome/common/chrome_switches.h" |
-#include "chrome/common/pref_names.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "google_apis/gaia/gaia_constants.h" |
-#include "google_apis/gaia/gaia_urls.h" |
-#include "net/base/escape.h" |
-#include "net/base/load_flags.h" |
-#include "net/http/http_request_headers.h" |
-#include "net/http/http_status_code.h" |
-#include "net/url_request/url_fetcher.h" |
-#include "net/url_request/url_request_status.h" |
- |
-using base::StringPrintf; |
-using content::BrowserThread; |
-using net::URLFetcher; |
- |
-namespace extensions { |
- |
-namespace { |
- |
-static const char kChannelSetupAuthError[] = "unauthorized"; |
-static const char kChannelSetupInternalError[] = "internal_error"; |
-static const char kChannelSetupCanceledByUser[] = "canceled_by_user"; |
-static const char kAuthorizationHeaderFormat[] = |
- "Authorization: Bearer %s"; |
-static const char kOAuth2IssueTokenURL[] = |
- "https://www.googleapis.com/oauth2/v2/IssueToken"; |
-static const char kOAuth2IssueTokenBodyFormat[] = |
- "force=true" |
- "&response_type=token" |
- "&scope=%s" |
- "&client_id=%s" |
- "&origin=%s"; |
-static const char kOAuth2IssueTokenScope[] = |
- "https://www.googleapis.com/auth/chromewebstore.notification"; |
-static const char kCWSChannelServiceURL[] = |
- "https://www.googleapis.com/chromewebstore/v1.1/channels/id"; |
- |
-static AppNotifyChannelSetup::InterceptorForTests* |
- g_interceptor_for_tests = NULL; |
- |
-} // namespace. |
- |
-// static |
-void AppNotifyChannelSetup::SetInterceptorForTests( |
- AppNotifyChannelSetup::InterceptorForTests* interceptor) { |
- // Only one interceptor at a time, please. |
- CHECK(g_interceptor_for_tests == NULL); |
- g_interceptor_for_tests = interceptor; |
-} |
- |
-AppNotifyChannelSetup::AppNotifyChannelSetup( |
- Profile* profile, |
- const std::string& extension_id, |
- const std::string& client_id, |
- const GURL& requestor_url, |
- int return_route_id, |
- int callback_id, |
- AppNotifyChannelUI* ui, |
- base::WeakPtr<AppNotifyChannelSetup::Delegate> delegate) |
- : profile_(profile->GetOriginalProfile()), |
- extension_id_(extension_id), |
- client_id_(client_id), |
- requestor_url_(requestor_url), |
- return_route_id_(return_route_id), |
- callback_id_(callback_id), |
- delegate_(delegate), |
- ui_(ui), |
- state_(INITIAL), |
- oauth2_access_token_failure_(false) {} |
- |
-AppNotifyChannelSetup::~AppNotifyChannelSetup() {} |
- |
-void AppNotifyChannelSetup::Start() { |
- AddRef(); // Balanced in ReportResult. |
- |
- if (g_interceptor_for_tests) { |
- std::string channel_id; |
- SetupError error; |
- g_interceptor_for_tests->DoIntercept(this, &channel_id, &error); |
- state_ = error == NONE ? CHANNEL_ID_SETUP_DONE : ERROR_STATE; |
- |
- // Use PostTask so the message loop runs before notifying the delegate, like |
- // in the real implementation. |
- MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&AppNotifyChannelSetup::ReportResult, |
- base::Unretained(this), channel_id, error)); |
- return; |
- } |
- |
- BeginLogin(); |
-} |
- |
-void AppNotifyChannelSetup::OnGetTokenSuccess( |
- const std::string& access_token, |
- const base::Time& expiration_time) { |
- oauth2_access_token_ = access_token; |
- EndGetAccessToken(true); |
-} |
-void AppNotifyChannelSetup::OnGetTokenFailure( |
- const GoogleServiceAuthError& error) { |
- EndGetAccessToken(false); |
-} |
- |
-void AppNotifyChannelSetup::OnSyncSetupResult(bool enabled) { |
- EndLogin(enabled); |
-} |
- |
-void AppNotifyChannelSetup::OnURLFetchComplete(const net::URLFetcher* source) { |
- CHECK(source); |
- switch (state_) { |
- case RECORD_GRANT_STARTED: |
- EndRecordGrant(source); |
- break; |
- case CHANNEL_ID_SETUP_STARTED: |
- EndGetChannelId(source); |
- break; |
- default: |
- CHECK(false) << "Wrong state: " << state_; |
- break; |
- } |
-} |
- |
-// The contents of |body| should be URL-encoded as appropriate. |
-URLFetcher* AppNotifyChannelSetup::CreateURLFetcher( |
- const GURL& url, const std::string& body, const std::string& auth_token) { |
- CHECK(url.is_valid()); |
- URLFetcher::RequestType type = |
- body.empty() ? URLFetcher::GET : URLFetcher::POST; |
- URLFetcher* fetcher = net::URLFetcher::Create(0, url, type, this); |
- fetcher->SetRequestContext(profile_->GetRequestContext()); |
- // Always set flags to neither send nor save cookies. |
- fetcher->SetLoadFlags( |
- net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); |
- fetcher->SetExtraRequestHeaders(MakeAuthorizationHeader(auth_token)); |
- if (!body.empty()) { |
- fetcher->SetUploadData("application/x-www-form-urlencoded", body); |
- } |
- return fetcher; |
-} |
- |
-bool AppNotifyChannelSetup::ShouldPromptForLogin() const { |
- std::string username = |
- SigninManagerFactory::GetForProfile(profile_)->GetAuthenticatedUsername(); |
- // Prompt for login if either: |
- // 1. the user has not logged in at all or |
- // 2. if the user is logged in but there is no OAuth2 login token. |
- // The latter happens for users who are already logged in before the |
- // code to generate OAuth2 login token is released. |
- // 3. If the OAuth2 login token does not work anymore. |
- // This can happen if the user explicitly revoked access to Google Chrome |
- // from Google Accounts page. |
- return username.empty() || |
- !TokenServiceFactory::GetForProfile(profile_)->HasOAuthLoginToken() || |
- oauth2_access_token_failure_; |
-} |
- |
-namespace { |
- |
-enum LoginNeededHistogram { |
- LOGIN_NEEDED, |
- LOGIN_NOT_NEEDED, |
- LOGIN_NEEDED_BOUNDARY |
-}; |
- |
-enum LoginSuccessHistogram { |
- LOGIN_SUCCESS, |
- LOGIN_FAILURE, |
- LOGIN_SUCCESS_BOUNDARY |
-}; |
- |
-} // namespace |
- |
-void AppNotifyChannelSetup::BeginLogin() { |
- CHECK_EQ(INITIAL, state_); |
- state_ = LOGIN_STARTED; |
- bool login_needed = ShouldPromptForLogin(); |
- UMA_HISTOGRAM_ENUMERATION("AppNotify.ChannelSetupBegin", |
- login_needed ? LOGIN_NEEDED : LOGIN_NOT_NEEDED, |
- LOGIN_NEEDED_BOUNDARY); |
- if (login_needed) { |
- ui_->PromptSyncSetup(this); |
- // We'll get called back in OnSyncSetupResult |
- } else { |
- EndLogin(true); |
- } |
-} |
- |
-void AppNotifyChannelSetup::EndLogin(bool success) { |
- CHECK_EQ(LOGIN_STARTED, state_); |
- UMA_HISTOGRAM_ENUMERATION("AppNotify.ChannelSetupLoginResult", |
- success ? LOGIN_SUCCESS : LOGIN_FAILURE, |
- LOGIN_SUCCESS_BOUNDARY); |
- if (success) { |
- state_ = LOGIN_DONE; |
- BeginGetAccessToken(); |
- } else { |
- state_ = ERROR_STATE; |
- ReportResult("", USER_CANCELLED); |
- } |
-} |
- |
-void AppNotifyChannelSetup::BeginGetAccessToken() { |
- CHECK_EQ(LOGIN_DONE, state_); |
- state_ = FETCH_ACCESS_TOKEN_STARTED; |
- |
- oauth2_fetcher_.reset(new OAuth2AccessTokenFetcher( |
- this, profile_->GetRequestContext())); |
- std::vector<std::string> scopes; |
- scopes.push_back(GaiaUrls::GetInstance()->oauth1_login_scope()); |
- scopes.push_back(kOAuth2IssueTokenScope); |
- TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
- oauth2_fetcher_->Start( |
- GaiaUrls::GetInstance()->oauth2_chrome_client_id(), |
- GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), |
- token_service->GetOAuth2LoginRefreshToken(), |
- scopes); |
-} |
- |
-void AppNotifyChannelSetup::EndGetAccessToken(bool success) { |
- CHECK_EQ(FETCH_ACCESS_TOKEN_STARTED, state_); |
- if (success) { |
- state_ = FETCH_ACCESS_TOKEN_DONE; |
- BeginRecordGrant(); |
- } else if (!oauth2_access_token_failure_) { |
- oauth2_access_token_failure_ = true; |
- // If access token generation fails, then it means somehow the |
- // OAuth2 login scoped token became invalid. One way this can happen |
- // is if a user explicitly revoked access to Google Chrome from |
- // Google Accounts page. In such a case, we should try to show the |
- // login setup again to the user, but only if we have not already |
- // done so once (to avoid infinite loop). |
- state_ = INITIAL; |
- BeginLogin(); |
- } else { |
- state_ = ERROR_STATE; |
- ReportResult("", INTERNAL_ERROR); |
- } |
-} |
- |
-void AppNotifyChannelSetup::BeginRecordGrant() { |
- CHECK_EQ(FETCH_ACCESS_TOKEN_DONE, state_); |
- state_ = RECORD_GRANT_STARTED; |
- |
- GURL url = GetOAuth2IssueTokenURL(); |
- std::string body = MakeOAuth2IssueTokenBody(client_id_, extension_id_); |
- |
- url_fetcher_.reset(CreateURLFetcher(url, body, oauth2_access_token_)); |
- url_fetcher_->Start(); |
-} |
- |
-void AppNotifyChannelSetup::EndRecordGrant(const net::URLFetcher* source) { |
- CHECK_EQ(RECORD_GRANT_STARTED, state_); |
- |
- net::URLRequestStatus status = source->GetStatus(); |
- |
- if (status.status() == net::URLRequestStatus::SUCCESS) { |
- if (source->GetResponseCode() == net::HTTP_OK) { |
- state_ = RECORD_GRANT_DONE; |
- BeginGetChannelId(); |
- } else { |
- // Successfully done with HTTP request, but got an explicit error. |
- state_ = ERROR_STATE; |
- ReportResult("", AUTH_ERROR); |
- } |
- } else { |
- // Could not do HTTP request. |
- state_ = ERROR_STATE; |
- ReportResult("", INTERNAL_ERROR); |
- } |
-} |
- |
-void AppNotifyChannelSetup::BeginGetChannelId() { |
- CHECK_EQ(RECORD_GRANT_DONE, state_); |
- state_ = CHANNEL_ID_SETUP_STARTED; |
- |
- GURL url = GetCWSChannelServiceURL(); |
- |
- url_fetcher_.reset(CreateURLFetcher(url, "", oauth2_access_token_)); |
- url_fetcher_->Start(); |
-} |
- |
-void AppNotifyChannelSetup::EndGetChannelId(const net::URLFetcher* source) { |
- CHECK_EQ(CHANNEL_ID_SETUP_STARTED, state_); |
- net::URLRequestStatus status = source->GetStatus(); |
- |
- if (status.status() == net::URLRequestStatus::SUCCESS) { |
- if (source->GetResponseCode() == net::HTTP_OK) { |
- std::string data; |
- source->GetResponseAsString(&data); |
- std::string channel_id; |
- bool result = ParseCWSChannelServiceResponse(data, &channel_id); |
- if (result) { |
- state_ = CHANNEL_ID_SETUP_DONE; |
- ReportResult(channel_id, NONE); |
- } else { |
- state_ = ERROR_STATE; |
- ReportResult("", INTERNAL_ERROR); |
- } |
- } else { |
- // Successfully done with HTTP request, but got an explicit error. |
- state_ = ERROR_STATE; |
- ReportResult("", AUTH_ERROR); |
- } |
- } else { |
- // Could not do HTTP request. |
- state_ = ERROR_STATE; |
- ReportResult("", INTERNAL_ERROR); |
- } |
-} |
- |
-void AppNotifyChannelSetup::ReportResult( |
- const std::string& channel_id, |
- SetupError error) { |
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- CHECK(state_ == CHANNEL_ID_SETUP_DONE || state_ == ERROR_STATE); |
- |
- UMA_HISTOGRAM_ENUMERATION("AppNotification.ChannelSetupFinalResult", |
- error, SETUP_ERROR_BOUNDARY); |
- if (delegate_.get()) { |
- delegate_->AppNotifyChannelSetupComplete( |
- channel_id, GetErrorString(error), this); |
- } |
- Release(); // Matches AddRef in Start. |
-} |
- |
-// static |
-std::string AppNotifyChannelSetup::GetErrorString(SetupError error) { |
- switch (error) { |
- case NONE: return ""; |
- case AUTH_ERROR: return kChannelSetupAuthError; |
- case INTERNAL_ERROR: return kChannelSetupInternalError; |
- case USER_CANCELLED: return kChannelSetupCanceledByUser; |
- case SETUP_ERROR_BOUNDARY: { |
- CHECK(false); |
- break; |
- } |
- } |
- CHECK(false) << "Unhandled enum value"; |
- return std::string(); |
-} |
- |
- |
-// static |
-GURL AppNotifyChannelSetup::GetCWSChannelServiceURL() { |
- CommandLine* command_line = CommandLine::ForCurrentProcess(); |
- if (command_line->HasSwitch(switches::kAppNotifyChannelServerURL)) { |
- std::string switch_value = command_line->GetSwitchValueASCII( |
- switches::kAppNotifyChannelServerURL); |
- GURL result(switch_value); |
- if (result.is_valid()) { |
- return result; |
- } else { |
- LOG(ERROR) << "Invalid value for " << |
- switches::kAppNotifyChannelServerURL; |
- } |
- } |
- return GURL(kCWSChannelServiceURL); |
-} |
- |
-// static |
-GURL AppNotifyChannelSetup::GetOAuth2IssueTokenURL() { |
- return GURL(kOAuth2IssueTokenURL); |
-} |
- |
-// static |
-std::string AppNotifyChannelSetup::MakeOAuth2IssueTokenBody( |
- const std::string& oauth_client_id, |
- const std::string& extension_id) { |
- return StringPrintf(kOAuth2IssueTokenBodyFormat, |
- kOAuth2IssueTokenScope, |
- net::EscapeUrlEncodedData(oauth_client_id, true).c_str(), |
- net::EscapeUrlEncodedData(extension_id, true).c_str()); |
-} |
- |
-// static |
-std::string AppNotifyChannelSetup::MakeAuthorizationHeader( |
- const std::string& auth_token) { |
- return StringPrintf(kAuthorizationHeaderFormat, auth_token.c_str()); |
-} |
- |
-// static |
-bool AppNotifyChannelSetup::ParseCWSChannelServiceResponse( |
- const std::string& data, std::string* result) { |
- scoped_ptr<base::Value> value(base::JSONReader::Read(data)); |
- if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) |
- return false; |
- |
- DictionaryValue* dict = static_cast<DictionaryValue*>(value.get()); |
- return dict->GetString("id", result); |
-} |
- |
-} // namespace extensions |