cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / google_apis / gaia / oauth2_mint_token_flow.cc
blobf66e0fb11d2e1f12958703cfa504b8a6dc212a6c
1 // Copyright (c) 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 "google_apis/gaia/oauth2_mint_token_flow.h"
7 #include <string>
8 #include <vector>
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/json/json_reader.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/values.h"
20 #include "google_apis/gaia/gaia_urls.h"
21 #include "google_apis/gaia/google_service_auth_error.h"
22 #include "net/base/escape.h"
23 #include "net/url_request/url_fetcher.h"
24 #include "net/url_request/url_request_context_getter.h"
25 #include "net/url_request/url_request_status.h"
27 using net::URLFetcher;
28 using net::URLRequestContextGetter;
29 using net::URLRequestStatus;
31 namespace {
33 static const char kForceValueFalse[] = "false";
34 static const char kForceValueTrue[] = "true";
35 static const char kResponseTypeValueNone[] = "none";
36 static const char kResponseTypeValueToken[] = "token";
38 static const char kOAuth2IssueTokenBodyFormat[] =
39 "force=%s"
40 "&response_type=%s"
41 "&scope=%s"
42 "&client_id=%s"
43 "&origin=%s";
44 static const char kIssueAdviceKey[] = "issueAdvice";
45 static const char kIssueAdviceValueAuto[] = "auto";
46 static const char kIssueAdviceValueConsent[] = "consent";
47 static const char kAccessTokenKey[] = "token";
48 static const char kConsentKey[] = "consent";
49 static const char kExpiresInKey[] = "expiresIn";
50 static const char kScopesKey[] = "scopes";
51 static const char kDescriptionKey[] = "description";
52 static const char kDetailKey[] = "detail";
53 static const char kDetailSeparators[] = "\n";
54 static const char kError[] = "error";
55 static const char kMessage[] = "message";
57 static GoogleServiceAuthError CreateAuthError(const net::URLFetcher* source) {
58 URLRequestStatus status = source->GetStatus();
59 if (status.status() == URLRequestStatus::CANCELED) {
60 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
62 if (status.status() == URLRequestStatus::FAILED) {
63 DLOG(WARNING) << "Server returned error: errno " << status.error();
64 return GoogleServiceAuthError::FromConnectionError(status.error());
67 std::string response_body;
68 source->GetResponseAsString(&response_body);
69 scoped_ptr<Value> value(base::JSONReader::Read(response_body));
70 DictionaryValue* response;
71 if (!value.get() || !value->GetAsDictionary(&response)) {
72 return GoogleServiceAuthError::FromUnexpectedServiceResponse(
73 base::StringPrintf(
74 "Not able to parse a JSON object from a service response. "
75 "HTTP Status of the response is: %d", source->GetResponseCode()));
77 DictionaryValue* error;
78 if (!response->GetDictionary(kError, &error)) {
79 return GoogleServiceAuthError::FromUnexpectedServiceResponse(
80 "Not able to find a detailed error in a service response.");
82 std::string message;
83 if (!error->GetString(kMessage, &message)) {
84 return GoogleServiceAuthError::FromUnexpectedServiceResponse(
85 "Not able to find an error message within a service error.");
87 return GoogleServiceAuthError::FromServiceError(message);
90 } // namespace
92 IssueAdviceInfoEntry::IssueAdviceInfoEntry() {}
93 IssueAdviceInfoEntry::~IssueAdviceInfoEntry() {}
95 bool IssueAdviceInfoEntry::operator ==(const IssueAdviceInfoEntry& rhs) const {
96 return description == rhs.description && details == rhs.details;
99 OAuth2MintTokenFlow::Parameters::Parameters() : mode(MODE_ISSUE_ADVICE) {}
101 OAuth2MintTokenFlow::Parameters::Parameters(
102 const std::string& at,
103 const std::string& eid,
104 const std::string& cid,
105 const std::vector<std::string>& scopes_arg,
106 Mode mode_arg)
107 : access_token(at),
108 extension_id(eid),
109 client_id(cid),
110 scopes(scopes_arg),
111 mode(mode_arg) {
114 OAuth2MintTokenFlow::Parameters::~Parameters() {}
116 OAuth2MintTokenFlow::OAuth2MintTokenFlow(URLRequestContextGetter* context,
117 Delegate* delegate,
118 const Parameters& parameters)
119 : OAuth2ApiCallFlow(context,
120 std::string(),
121 parameters.access_token,
122 std::vector<std::string>()),
123 delegate_(delegate),
124 parameters_(parameters),
125 weak_factory_(this) {}
127 OAuth2MintTokenFlow::~OAuth2MintTokenFlow() { }
129 void OAuth2MintTokenFlow::ReportSuccess(const std::string& access_token,
130 int time_to_live) {
131 if (delegate_)
132 delegate_->OnMintTokenSuccess(access_token, time_to_live);
134 // |this| may already be deleted.
137 void OAuth2MintTokenFlow::ReportIssueAdviceSuccess(
138 const IssueAdviceInfo& issue_advice) {
139 if (delegate_)
140 delegate_->OnIssueAdviceSuccess(issue_advice);
142 // |this| may already be deleted.
145 void OAuth2MintTokenFlow::ReportFailure(
146 const GoogleServiceAuthError& error) {
147 if (delegate_)
148 delegate_->OnMintTokenFailure(error);
150 // |this| may already be deleted.
153 GURL OAuth2MintTokenFlow::CreateApiCallUrl() {
154 return GURL(GaiaUrls::GetInstance()->oauth2_issue_token_url());
157 std::string OAuth2MintTokenFlow::CreateApiCallBody() {
158 const char* force_value =
159 (parameters_.mode == MODE_MINT_TOKEN_FORCE ||
160 parameters_.mode == MODE_RECORD_GRANT)
161 ? kForceValueTrue : kForceValueFalse;
162 const char* response_type_value =
163 (parameters_.mode == MODE_MINT_TOKEN_NO_FORCE ||
164 parameters_.mode == MODE_MINT_TOKEN_FORCE)
165 ? kResponseTypeValueToken : kResponseTypeValueNone;
166 return base::StringPrintf(
167 kOAuth2IssueTokenBodyFormat,
168 net::EscapeUrlEncodedData(force_value, true).c_str(),
169 net::EscapeUrlEncodedData(response_type_value, true).c_str(),
170 net::EscapeUrlEncodedData(
171 JoinString(parameters_.scopes, ' '), true).c_str(),
172 net::EscapeUrlEncodedData(parameters_.client_id, true).c_str(),
173 net::EscapeUrlEncodedData(parameters_.extension_id, true).c_str());
176 void OAuth2MintTokenFlow::ProcessApiCallSuccess(
177 const net::URLFetcher* source) {
178 std::string response_body;
179 source->GetResponseAsString(&response_body);
180 scoped_ptr<base::Value> value(base::JSONReader::Read(response_body));
181 base::DictionaryValue* dict = NULL;
182 if (!value.get() || !value->GetAsDictionary(&dict)) {
183 ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse(
184 "Not able to parse a JSON object from a service response."));
185 return;
188 std::string issue_advice_value;
189 if (!dict->GetString(kIssueAdviceKey, &issue_advice_value)) {
190 ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse(
191 "Not able to find an issueAdvice in a service response."));
192 return;
194 if (issue_advice_value == kIssueAdviceValueConsent) {
195 IssueAdviceInfo issue_advice;
196 if (ParseIssueAdviceResponse(dict, &issue_advice))
197 ReportIssueAdviceSuccess(issue_advice);
198 else
199 ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse(
200 "Not able to parse the contents of consent "
201 "from a service response."));
202 } else {
203 std::string access_token;
204 int time_to_live;
205 if (ParseMintTokenResponse(dict, &access_token, &time_to_live))
206 ReportSuccess(access_token, time_to_live);
207 else
208 ReportFailure(GoogleServiceAuthError::FromUnexpectedServiceResponse(
209 "Not able to parse the contents of access token "
210 "from a service response."));
213 // |this| may be deleted!
216 void OAuth2MintTokenFlow::ProcessApiCallFailure(
217 const net::URLFetcher* source) {
218 ReportFailure(CreateAuthError(source));
220 void OAuth2MintTokenFlow::ProcessNewAccessToken(
221 const std::string& access_token) {
222 // We don't currently store new access tokens. We generate one every time.
223 // So we have nothing to do here.
224 return;
226 void OAuth2MintTokenFlow::ProcessMintAccessTokenFailure(
227 const GoogleServiceAuthError& error) {
228 ReportFailure(error);
231 // static
232 bool OAuth2MintTokenFlow::ParseMintTokenResponse(
233 const base::DictionaryValue* dict, std::string* access_token,
234 int* time_to_live) {
235 CHECK(dict);
236 CHECK(access_token);
237 CHECK(time_to_live);
238 std::string ttl_string;
239 return dict->GetString(kExpiresInKey, &ttl_string) &&
240 base::StringToInt(ttl_string, time_to_live) &&
241 dict->GetString(kAccessTokenKey, access_token);
244 // static
245 bool OAuth2MintTokenFlow::ParseIssueAdviceResponse(
246 const base::DictionaryValue* dict, IssueAdviceInfo* issue_advice) {
247 CHECK(dict);
248 CHECK(issue_advice);
250 const base::DictionaryValue* consent_dict = NULL;
251 if (!dict->GetDictionary(kConsentKey, &consent_dict))
252 return false;
254 const base::ListValue* scopes_list = NULL;
255 if (!consent_dict->GetList(kScopesKey, &scopes_list))
256 return false;
258 bool success = true;
259 for (size_t index = 0; index < scopes_list->GetSize(); ++index) {
260 const base::DictionaryValue* scopes_entry = NULL;
261 IssueAdviceInfoEntry entry;
262 string16 detail;
263 if (!scopes_list->GetDictionary(index, &scopes_entry) ||
264 !scopes_entry->GetString(kDescriptionKey, &entry.description) ||
265 !scopes_entry->GetString(kDetailKey, &detail)) {
266 success = false;
267 break;
270 TrimWhitespace(entry.description, TRIM_ALL, &entry.description);
271 static const string16 detail_separators = ASCIIToUTF16(kDetailSeparators);
272 Tokenize(detail, detail_separators, &entry.details);
273 for (size_t i = 0; i < entry.details.size(); i++)
274 TrimWhitespace(entry.details[i], TRIM_ALL, &entry.details[i]);
275 issue_advice->push_back(entry);
278 if (!success)
279 issue_advice->clear();
281 return success;