OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/extensions/app_notify_channel_setup.h" | 5 #include "chrome/browser/extensions/app_notify_channel_setup.h" |
6 | 6 |
| 7 #include "base/basictypes.h" |
7 #include "base/bind.h" | 8 #include "base/bind.h" |
8 #include "base/command_line.h" | 9 #include "base/command_line.h" |
9 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
10 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
11 #include "chrome/browser/net/gaia/token_service.h" | 12 #include "chrome/browser/net/gaia/token_service.h" |
12 #include "chrome/browser/prefs/pref_service.h" | 13 #include "chrome/browser/prefs/pref_service.h" |
13 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/common/chrome_notification_types.h" |
14 #include "chrome/common/chrome_switches.h" | 16 #include "chrome/common/chrome_switches.h" |
15 #include "chrome/common/net/gaia/gaia_constants.h" | 17 #include "chrome/common/net/gaia/gaia_constants.h" |
16 #include "chrome/common/net/http_return.h" | 18 #include "chrome/common/net/http_return.h" |
17 #include "chrome/common/pref_names.h" | 19 #include "chrome/common/pref_names.h" |
18 #include "content/public/browser/browser_thread.h" | 20 #include "content/public/browser/browser_thread.h" |
| 21 #include "content/public/browser/notification_details.h" |
| 22 #include "content/public/browser/notification_service.h" |
19 #include "content/public/common/url_fetcher.h" | 23 #include "content/public/common/url_fetcher.h" |
20 #include "net/base/escape.h" | 24 #include "net/base/escape.h" |
21 #include "net/base/load_flags.h" | 25 #include "net/base/load_flags.h" |
22 #include "net/http/http_request_headers.h" | 26 #include "net/http/http_request_headers.h" |
23 #include "net/url_request/url_request_status.h" | 27 #include "net/url_request/url_request_status.h" |
24 | 28 |
25 using base::StringPrintf; | 29 using base::StringPrintf; |
26 using content::BrowserThread; | 30 using content::BrowserThread; |
27 using content::URLFetcher; | 31 using content::URLFetcher; |
28 | 32 |
(...skipping 10 matching lines...) Expand all Loading... |
39 "force=true" | 43 "force=true" |
40 "&response_type=token" | 44 "&response_type=token" |
41 "&scope=%s" | 45 "&scope=%s" |
42 "&client_id=%s" | 46 "&client_id=%s" |
43 "&origin=%s"; | 47 "&origin=%s"; |
44 static const char kOAuth2IssueTokenScope[] = | 48 static const char kOAuth2IssueTokenScope[] = |
45 "https://www.googleapis.com/auth/chromewebstore.notification"; | 49 "https://www.googleapis.com/auth/chromewebstore.notification"; |
46 static const char kCWSChannelServiceURL[] = | 50 static const char kCWSChannelServiceURL[] = |
47 "https://www-googleapis-staging.sandbox.google.com/chromewebstore/" | 51 "https://www-googleapis-staging.sandbox.google.com/chromewebstore/" |
48 "v1internal/channels/app_id/oauth_client_id"; | 52 "v1internal/channels/app_id/oauth_client_id"; |
| 53 static const char* kRelevantGaiaServices[] = { |
| 54 GaiaConstants::kCWSService, |
| 55 GaiaConstants::kLSOService, |
| 56 }; |
| 57 static const int kRelevantGaiaServicesCount = arraysize(kRelevantGaiaServices); |
49 } // namespace. | 58 } // namespace. |
50 | 59 |
51 AppNotifyChannelSetup::AppNotifyChannelSetup( | 60 AppNotifyChannelSetup::AppNotifyChannelSetup( |
52 Profile* profile, | 61 Profile* profile, |
53 const std::string& extension_id, | 62 const std::string& extension_id, |
54 const std::string& client_id, | 63 const std::string& client_id, |
55 const GURL& requestor_url, | 64 const GURL& requestor_url, |
56 int return_route_id, | 65 int return_route_id, |
57 int callback_id, | 66 int callback_id, |
58 AppNotifyChannelUI* ui, | 67 AppNotifyChannelUI* ui, |
59 base::WeakPtr<AppNotifyChannelSetup::Delegate> delegate) | 68 base::WeakPtr<AppNotifyChannelSetup::Delegate> delegate) |
60 : profile_(profile), | 69 : profile_(profile), |
61 extension_id_(extension_id), | 70 extension_id_(extension_id), |
62 client_id_(client_id), | 71 client_id_(client_id), |
63 requestor_url_(requestor_url), | 72 requestor_url_(requestor_url), |
64 return_route_id_(return_route_id), | 73 return_route_id_(return_route_id), |
65 callback_id_(callback_id), | 74 callback_id_(callback_id), |
66 delegate_(delegate), | 75 delegate_(delegate), |
67 ui_(ui), | 76 ui_(ui), |
68 state_(INITIAL) {} | 77 state_(INITIAL), |
| 78 fetch_token_success_count_(0), |
| 79 fetch_token_fail_count_(0) {} |
69 | 80 |
70 AppNotifyChannelSetup::~AppNotifyChannelSetup() {} | 81 AppNotifyChannelSetup::~AppNotifyChannelSetup() {} |
71 | 82 |
72 void AppNotifyChannelSetup::Start() { | 83 void AppNotifyChannelSetup::Start() { |
73 AddRef(); // Balanced in ReportResult. | 84 AddRef(); // Balanced in ReportResult. |
| 85 BeginLogin(); |
| 86 } |
74 | 87 |
75 CHECK_EQ(INITIAL, state_); | 88 void AppNotifyChannelSetup::Observe( |
76 | 89 int type, |
77 // Check if the user is logged in to the browser. | 90 const content::NotificationSource& source, |
78 std::string username = profile_->GetPrefs()->GetString( | 91 const content::NotificationDetails& details) { |
79 prefs::kGoogleServicesUsername); | 92 if (type == chrome::NOTIFICATION_TOKEN_AVAILABLE) { |
80 | 93 TokenService::TokenAvailableDetails* tok_details = |
81 if (username.empty()) { | 94 content::Details<TokenService::TokenAvailableDetails>(details).ptr(); |
82 state_ = LOGIN_STARTED; | 95 if (IsGaiaServiceRelevant(tok_details->service())) |
83 ui_->PromptSyncSetup(this); | 96 ++fetch_token_success_count_; |
84 return; // We'll get called back in OnSyncSetupResult | 97 } else if (type == chrome::NOTIFICATION_TOKEN_REQUEST_FAILED) { |
| 98 TokenService::TokenRequestFailedDetails* error_details = |
| 99 content::Details<TokenService::TokenRequestFailedDetails>( |
| 100 details).ptr(); |
| 101 if (IsGaiaServiceRelevant(error_details->service())) |
| 102 ++fetch_token_fail_count_; |
| 103 } else { |
| 104 CHECK(false) << "Received a notification not registered for."; |
85 } | 105 } |
86 | 106 |
87 state_ = LOGIN_DONE; | 107 // If we already got fetch results (success + failure) for all services |
88 BeginRecordGrant(); | 108 // we care about, we are done with fetching tokens. |
| 109 if (fetch_token_success_count_ + fetch_token_fail_count_ == |
| 110 kRelevantGaiaServicesCount) { |
| 111 UnregisterForTokenServiceNotifications(); |
| 112 // We successfully fetched tokens if success count is equal to the |
| 113 // number of services we care about. |
| 114 bool success = (fetch_token_success_count_ == kRelevantGaiaServicesCount); |
| 115 EndFetchTokens(success); |
| 116 } |
| 117 } |
| 118 |
| 119 bool AppNotifyChannelSetup::ShouldFetchServiceTokens() const { |
| 120 TokenService* token_service = profile_->GetTokenService(); |
| 121 for (int i = 0; i < kRelevantGaiaServicesCount; ++i) { |
| 122 if (!token_service->HasTokenForService(kRelevantGaiaServices[i])) |
| 123 return true; |
| 124 } |
| 125 return false; |
89 } | 126 } |
90 | 127 |
91 void AppNotifyChannelSetup::OnSyncSetupResult(bool enabled) { | 128 void AppNotifyChannelSetup::OnSyncSetupResult(bool enabled) { |
92 CHECK_EQ(LOGIN_STARTED, state_); | 129 EndLogin(enabled); |
93 if (enabled) { | |
94 state_ = LOGIN_DONE; | |
95 BeginRecordGrant(); | |
96 } else { | |
97 state_ = ERROR_STATE; | |
98 ReportResult("", kChannelSetupCanceledByUser); | |
99 } | |
100 } | 130 } |
101 | 131 |
102 void AppNotifyChannelSetup::OnURLFetchComplete(const URLFetcher* source) { | 132 void AppNotifyChannelSetup::OnURLFetchComplete(const URLFetcher* source) { |
103 CHECK(source); | 133 CHECK(source); |
104 | |
105 switch (state_) { | 134 switch (state_) { |
106 case RECORD_GRANT_STARTED: | 135 case RECORD_GRANT_STARTED: |
107 EndRecordGrant(source); | 136 EndRecordGrant(source); |
108 break; | 137 break; |
109 case CHANNEL_ID_SETUP_STARTED: | 138 case CHANNEL_ID_SETUP_STARTED: |
110 EndGetChannelId(source); | 139 EndGetChannelId(source); |
111 break; | 140 break; |
112 default: | 141 default: |
113 CHECK(false) << "Wrong state: " << state_; | 142 CHECK(false) << "Wrong state: " << state_; |
114 break; | 143 break; |
(...skipping 11 matching lines...) Expand all Loading... |
126 // Always set flags to neither send nor save cookies. | 155 // Always set flags to neither send nor save cookies. |
127 fetcher->SetLoadFlags( | 156 fetcher->SetLoadFlags( |
128 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); | 157 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); |
129 fetcher->SetExtraRequestHeaders(MakeAuthorizationHeader(auth_token)); | 158 fetcher->SetExtraRequestHeaders(MakeAuthorizationHeader(auth_token)); |
130 if (!body.empty()) { | 159 if (!body.empty()) { |
131 fetcher->SetUploadData("application/x-www-form-urlencoded", body); | 160 fetcher->SetUploadData("application/x-www-form-urlencoded", body); |
132 } | 161 } |
133 return fetcher; | 162 return fetcher; |
134 } | 163 } |
135 | 164 |
| 165 // static |
| 166 bool AppNotifyChannelSetup::IsGaiaServiceRelevant(const std::string& service) { |
| 167 for (int i = 0; i < kRelevantGaiaServicesCount; ++i) { |
| 168 if (service == kRelevantGaiaServices[i]) |
| 169 return true; |
| 170 } |
| 171 return false; |
| 172 } |
| 173 |
| 174 void AppNotifyChannelSetup::RegisterForTokenServiceNotifications() { |
| 175 content::Source<TokenService> token_service(profile_->GetTokenService()); |
| 176 registrar_.Add(this, |
| 177 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 178 token_service); |
| 179 registrar_.Add(this, |
| 180 chrome::NOTIFICATION_TOKEN_REQUEST_FAILED, |
| 181 token_service); |
| 182 } |
| 183 |
| 184 void AppNotifyChannelSetup::UnregisterForTokenServiceNotifications() { |
| 185 registrar_.RemoveAll(); |
| 186 } |
| 187 |
| 188 bool AppNotifyChannelSetup::ShouldPromptForLogin() const { |
| 189 std::string username = profile_->GetPrefs()->GetString( |
| 190 prefs::kGoogleServicesUsername); |
| 191 return username.empty(); |
| 192 } |
| 193 |
| 194 void AppNotifyChannelSetup::BeginLogin() { |
| 195 CHECK_EQ(INITIAL, state_); |
| 196 state_ = LOGIN_STARTED; |
| 197 if (ShouldPromptForLogin()) { |
| 198 ui_->PromptSyncSetup(this); |
| 199 // We'll get called back in OnSyncSetupResult |
| 200 } else { |
| 201 EndLogin(true); |
| 202 } |
| 203 } |
| 204 |
| 205 void AppNotifyChannelSetup::EndLogin(bool success) { |
| 206 CHECK_EQ(LOGIN_STARTED, state_); |
| 207 if (success) { |
| 208 state_ = LOGIN_DONE; |
| 209 BeginFetchTokens(); |
| 210 } else { |
| 211 state_ = ERROR_STATE; |
| 212 ReportResult("", kChannelSetupCanceledByUser); |
| 213 } |
| 214 } |
| 215 |
| 216 void AppNotifyChannelSetup::BeginFetchTokens() { |
| 217 CHECK_EQ(LOGIN_DONE, state_); |
| 218 state_ = FETCH_TOKEN_STARTED; |
| 219 if (ShouldFetchServiceTokens()) { |
| 220 // If a user is logged in already, and a new version of Chrome is released |
| 221 // with new services added to Tokenservice, TokenService will not have |
| 222 // tokens for the new services. |
| 223 RegisterForTokenServiceNotifications(); |
| 224 profile_->GetTokenService()->StartFetchingMissingTokens(); |
| 225 // Observe will get called with notifications from TokenService. |
| 226 } else { |
| 227 EndFetchTokens(true); |
| 228 } |
| 229 } |
| 230 |
| 231 void AppNotifyChannelSetup::EndFetchTokens(bool success) { |
| 232 CHECK_EQ(FETCH_TOKEN_STARTED, state_); |
| 233 if (success) { |
| 234 state_ = FETCH_TOKEN_DONE; |
| 235 BeginRecordGrant(); |
| 236 } else { |
| 237 state_ = ERROR_STATE; |
| 238 ReportResult("", kChannelSetupInternalError); |
| 239 } |
| 240 } |
| 241 |
136 void AppNotifyChannelSetup::BeginRecordGrant() { | 242 void AppNotifyChannelSetup::BeginRecordGrant() { |
137 CHECK_EQ(LOGIN_DONE, state_); | 243 CHECK(FETCH_TOKEN_DONE == state_); |
138 state_ = RECORD_GRANT_STARTED; | 244 state_ = RECORD_GRANT_STARTED; |
139 | 245 |
140 GURL url = GetOAuth2IssueTokenURL(); | 246 GURL url = GetOAuth2IssueTokenURL(); |
141 std::string body = MakeOAuth2IssueTokenBody(client_id_, extension_id_); | 247 std::string body = MakeOAuth2IssueTokenBody(client_id_, extension_id_); |
142 | 248 |
143 url_fetcher_.reset(CreateURLFetcher(url, body, GetLSOAuthToken())); | 249 url_fetcher_.reset(CreateURLFetcher(url, body, GetLSOAuthToken())); |
144 url_fetcher_->Start(); | 250 url_fetcher_->Start(); |
145 } | 251 } |
146 | 252 |
147 void AppNotifyChannelSetup::EndRecordGrant(const URLFetcher* source) { | 253 void AppNotifyChannelSetup::EndRecordGrant(const URLFetcher* source) { |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 DictionaryValue* dict = static_cast<DictionaryValue*>(value.get()); | 371 DictionaryValue* dict = static_cast<DictionaryValue*>(value.get()); |
266 if (!dict->Get("id", &channel_id_value)) | 372 if (!dict->Get("id", &channel_id_value)) |
267 return false; | 373 return false; |
268 if (channel_id_value->GetType() != base::Value::TYPE_STRING) | 374 if (channel_id_value->GetType() != base::Value::TYPE_STRING) |
269 return false; | 375 return false; |
270 | 376 |
271 StringValue* channel_id = static_cast<StringValue*>(channel_id_value); | 377 StringValue* channel_id = static_cast<StringValue*>(channel_id_value); |
272 channel_id->GetAsString(result); | 378 channel_id->GetAsString(result); |
273 return true; | 379 return true; |
274 } | 380 } |
OLD | NEW |