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

Side by Side Diff: components/autofill/content/browser/wallet/wallet_client.cc

Issue 1288093004: rAc Wallet extirpation round 4: clean out RPC code (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: relative patchset Created 5 years, 4 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "components/autofill/content/browser/wallet/wallet_client.h"
6
7 #include "base/bind.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "components/autofill/content/browser/wallet/form_field_error.h"
18 #include "components/autofill/content/browser/wallet/instrument.h"
19 #include "components/autofill/content/browser/wallet/wallet_address.h"
20 #include "components/autofill/content/browser/wallet/wallet_client_delegate.h"
21 #include "components/autofill/content/browser/wallet/wallet_items.h"
22 #include "components/autofill/content/browser/wallet/wallet_service_url.h"
23 #include "components/autofill/core/browser/autofill_metrics.h"
24 #include "crypto/random.h"
25 #include "google_apis/google_api_keys.h"
26 #include "net/base/escape.h"
27 #include "net/http/http_status_code.h"
28 #include "net/url_request/url_fetcher.h"
29 #include "net/url_request/url_request_context_getter.h"
30
31 namespace autofill {
32 namespace wallet {
33
34 namespace {
35
36 const char kFormEncodedMimeType[] = "application/x-www-form-urlencoded";
37 const char kJsonMimeType[] = "application/json";
38 const char kEscrowNewInstrumentFormat[] =
39 "request_content_type=application/json&request=%s&cvn=%s&card_number=%s";
40 const char kEscrowCardVerificationNumberFormat[] =
41 "request_content_type=application/json&request=%s&cvn=%s";
42 const char kGetFullWalletRequestFormat[] =
43 "request_content_type=application/json&request=%s&otp=%s:%s";
44 const size_t kOneTimePadLength = 6;
45
46 // The maximum number of bits in the one time pad that the server is willing to
47 // accept.
48 const size_t kMaxBits = 56;
49
50 // The minimum number of bits in the one time pad that the server is willing to
51 // accept.
52 const size_t kMinBits = 40;
53
54 std::string RiskCapabilityToString(
55 WalletClient::RiskCapability risk_capability) {
56 switch (risk_capability) {
57 case WalletClient::RELOGIN:
58 return "RELOGIN";
59 case WalletClient::VERIFY_CVC:
60 return "VERIFY_CVC";
61 }
62 NOTREACHED();
63 return "NOT_POSSIBLE";
64 }
65
66 WalletClient::ErrorType StringToErrorType(const std::string& error_type) {
67 std::string trimmed;
68 base::TrimWhitespaceASCII(error_type, base::TRIM_ALL, &trimmed);
69 if (base::LowerCaseEqualsASCII(trimmed, "buyer_account_error"))
70 return WalletClient::BUYER_ACCOUNT_ERROR;
71 if (base::LowerCaseEqualsASCII(trimmed, "unsupported_merchant"))
72 return WalletClient::UNSUPPORTED_MERCHANT;
73 if (base::LowerCaseEqualsASCII(trimmed, "internal_error"))
74 return WalletClient::INTERNAL_ERROR;
75 if (base::LowerCaseEqualsASCII(trimmed, "invalid_params"))
76 return WalletClient::INVALID_PARAMS;
77 if (base::LowerCaseEqualsASCII(trimmed, "service_unavailable"))
78 return WalletClient::SERVICE_UNAVAILABLE;
79 if (base::LowerCaseEqualsASCII(trimmed, "unsupported_api_version"))
80 return WalletClient::UNSUPPORTED_API_VERSION;
81 if (base::LowerCaseEqualsASCII(trimmed, "unsupported_user_agent"))
82 return WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY;
83 if (base::LowerCaseEqualsASCII(trimmed, "spending_limit_exceeded"))
84 return WalletClient::SPENDING_LIMIT_EXCEEDED;
85
86 DVLOG(1) << "Unknown wallet error string: \"" << error_type << '"';
87 return WalletClient::UNKNOWN_ERROR;
88 }
89
90 // Get the more specific WalletClient::ErrorType when the error is
91 // |BUYER_ACCOUNT_ERROR|.
92 WalletClient::ErrorType BuyerErrorStringToErrorType(
93 const std::string& message_type_for_buyer) {
94 std::string trimmed;
95 base::TrimWhitespaceASCII(message_type_for_buyer, base::TRIM_ALL, &trimmed);
96 if (base::LowerCaseEqualsASCII(trimmed, "bla_country_not_supported"))
97 return WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED;
98 if (base::LowerCaseEqualsASCII(trimmed, "buyer_kyc_error"))
99 return WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS;
100
101 return WalletClient::BUYER_ACCOUNT_ERROR;
102 }
103
104 // Gets and parses required actions from a SaveToWallet response. Returns
105 // false if any unknown required actions are seen and true otherwise.
106 void GetRequiredActionsForSaveToWallet(
107 const base::DictionaryValue& dict,
108 std::vector<RequiredAction>* required_actions) {
109 const base::ListValue* required_action_list;
110 if (!dict.GetList("required_action", &required_action_list))
111 return;
112
113 for (size_t i = 0; i < required_action_list->GetSize(); ++i) {
114 std::string action_string;
115 if (required_action_list->GetString(i, &action_string)) {
116 RequiredAction action = ParseRequiredActionFromString(action_string);
117 if (!ActionAppliesToSaveToWallet(action)) {
118 DLOG(ERROR) << "Response from Google wallet with bad required action:"
119 " \"" << action_string << "\"";
120 required_actions->clear();
121 return;
122 }
123 required_actions->push_back(action);
124 }
125 }
126 }
127
128 void GetFormFieldErrors(const base::DictionaryValue& dict,
129 std::vector<FormFieldError>* form_errors) {
130 DCHECK(form_errors->empty());
131 const base::ListValue* form_errors_list;
132 if (!dict.GetList("form_field_error", &form_errors_list))
133 return;
134
135 for (size_t i = 0; i < form_errors_list->GetSize(); ++i) {
136 const base::DictionaryValue* dictionary;
137 if (form_errors_list->GetDictionary(i, &dictionary))
138 form_errors->push_back(FormFieldError::CreateFormFieldError(*dictionary));
139 }
140 }
141
142 // Converts the |error_type| to the corresponding value from the stable UMA
143 // metric enumeration.
144 AutofillMetrics::WalletErrorMetric ErrorTypeToUmaMetric(
145 WalletClient::ErrorType error_type) {
146 switch (error_type) {
147 case WalletClient::BAD_REQUEST:
148 return AutofillMetrics::WALLET_BAD_REQUEST;
149 case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
150 return AutofillMetrics::WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED;
151 case WalletClient::BUYER_ACCOUNT_ERROR:
152 return AutofillMetrics::WALLET_BUYER_ACCOUNT_ERROR;
153 case WalletClient::INTERNAL_ERROR:
154 return AutofillMetrics::WALLET_INTERNAL_ERROR;
155 case WalletClient::INVALID_PARAMS:
156 return AutofillMetrics::WALLET_INVALID_PARAMS;
157 case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
158 return AutofillMetrics::WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS;
159 case WalletClient::SERVICE_UNAVAILABLE:
160 return AutofillMetrics::WALLET_SERVICE_UNAVAILABLE;
161 case WalletClient::UNSUPPORTED_API_VERSION:
162 return AutofillMetrics::WALLET_UNSUPPORTED_API_VERSION;
163 case WalletClient::UNSUPPORTED_MERCHANT:
164 return AutofillMetrics::WALLET_UNSUPPORTED_MERCHANT;
165 case WalletClient::SPENDING_LIMIT_EXCEEDED:
166 return AutofillMetrics::WALLET_SPENDING_LIMIT_EXCEEDED;
167 case WalletClient::MALFORMED_RESPONSE:
168 return AutofillMetrics::WALLET_MALFORMED_RESPONSE;
169 case WalletClient::NETWORK_ERROR:
170 return AutofillMetrics::WALLET_NETWORK_ERROR;
171 case WalletClient::UNKNOWN_ERROR:
172 return AutofillMetrics::WALLET_UNKNOWN_ERROR;
173 case WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
174 return AutofillMetrics::WALLET_UNSUPPORTED_USER_AGENT_OR_API_KEY;
175 }
176
177 NOTREACHED();
178 return AutofillMetrics::WALLET_UNKNOWN_ERROR;
179 }
180
181 // Converts the |required_action| to the corresponding value from the stable UMA
182 // metric enumeration.
183 AutofillMetrics::WalletRequiredActionMetric RequiredActionToUmaMetric(
184 RequiredAction required_action) {
185 switch (required_action) {
186 case UNKNOWN_TYPE:
187 return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
188 case CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
189 return AutofillMetrics::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS;
190 case SETUP_WALLET:
191 return AutofillMetrics::SETUP_WALLET;
192 case ACCEPT_TOS:
193 return AutofillMetrics::ACCEPT_TOS;
194 case GAIA_AUTH:
195 return AutofillMetrics::GAIA_AUTH;
196 case UPDATE_EXPIRATION_DATE:
197 return AutofillMetrics::UPDATE_EXPIRATION_DATE;
198 case UPGRADE_MIN_ADDRESS:
199 return AutofillMetrics::UPGRADE_MIN_ADDRESS;
200 case INVALID_FORM_FIELD:
201 return AutofillMetrics::INVALID_FORM_FIELD;
202 case VERIFY_CVV:
203 return AutofillMetrics::VERIFY_CVV;
204 case PASSIVE_GAIA_AUTH:
205 return AutofillMetrics::PASSIVE_GAIA_AUTH;
206 case REQUIRE_PHONE_NUMBER:
207 return AutofillMetrics::REQUIRE_PHONE_NUMBER;
208 }
209
210 NOTREACHED();
211 return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
212 }
213
214 // Keys for JSON communication with the Online Wallet server.
215 const char kAcceptedLegalDocumentKey[] = "accepted_legal_document";
216 const char kApiKeyKey[] = "api_key";
217 const char kAuthResultKey[] = "auth_result";
218 const char kErrorTypeKey[] = "wallet_error.error_type";
219 const char kFeatureKey[] = "feature";
220 const char kGoogleTransactionIdKey[] = "google_transaction_id";
221 const char kInstrumentIdKey[] = "instrument_id";
222 const char kInstrumentKey[] = "instrument";
223 const char kInstrumentExpMonthKey[] = "instrument.credit_card.exp_month";
224 const char kInstrumentExpYearKey[] = "instrument.credit_card.exp_year";
225 const char kInstrumentType[] = "instrument.type";
226 const char kInstrumentPhoneNumberKey[] = "instrument_phone_number";
227 const char kMerchantDomainKey[] = "merchant_domain";
228 const char kMessageTypeForBuyerKey[] = "wallet_error.message_type_for_buyer";
229 const char kNewWalletUser[] = "new_wallet_user";
230 const char kPhoneNumberRequired[] = "phone_number_required";
231 const char kRiskCapabilitiesKey[] = "supported_risk_challenge";
232 const char kRiskParamsKey[] = "risk_params";
233 const char kSelectedAddressIdKey[] = "selected_address_id";
234 const char kSelectedInstrumentIdKey[] = "selected_instrument_id";
235 const char kShippingAddressIdKey[] = "shipping_address_id";
236 const char kShippingAddressKey[] = "shipping_address";
237 const char kShippingAddressRequired[] = "shipping_address_required";
238 const char kTransactionAmountKey[] = "estimated_total_price";
239 const char kTransactionCurrencyKey[] = "currency_code";
240 const char kUpgradedBillingAddressKey[] = "upgraded_billing_address";
241 const char kUpgradedInstrumentIdKey[] = "upgraded_instrument_id";
242 const char kUseMinimalAddresses[] = "use_minimal_addresses";
243
244 } // namespace
245
246 WalletClient::FullWalletRequest::FullWalletRequest(
247 const std::string& instrument_id,
248 const std::string& address_id,
249 const std::string& google_transaction_id,
250 const std::vector<RiskCapability> risk_capabilities,
251 bool new_wallet_user)
252 : instrument_id(instrument_id),
253 address_id(address_id),
254 google_transaction_id(google_transaction_id),
255 risk_capabilities(risk_capabilities),
256 new_wallet_user(new_wallet_user) {}
257
258 WalletClient::FullWalletRequest::~FullWalletRequest() {}
259
260 WalletClient::WalletClient(net::URLRequestContextGetter* context_getter,
261 WalletClientDelegate* delegate,
262 const GURL& source_url)
263 : context_getter_(context_getter),
264 delegate_(delegate),
265 user_index_(0U),
266 source_url_(source_url),
267 request_type_(NO_REQUEST),
268 one_time_pad_(kOneTimePadLength),
269 weak_ptr_factory_(this) {
270 DCHECK(context_getter_.get());
271 DCHECK(delegate_);
272 }
273
274 WalletClient::~WalletClient() {}
275
276 void WalletClient::AcceptLegalDocuments(
277 const std::vector<WalletItems::LegalDocument*>& documents,
278 const std::string& google_transaction_id) {
279 if (documents.empty())
280 return;
281
282 std::vector<std::string> document_ids;
283 for (size_t i = 0; i < documents.size(); ++i) {
284 document_ids.push_back(documents[i]->id());
285 }
286 DoAcceptLegalDocuments(document_ids, google_transaction_id);
287 }
288
289 void WalletClient::AuthenticateInstrument(
290 const std::string& instrument_id,
291 const std::string& card_verification_number) {
292 base::DictionaryValue request_dict;
293 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
294 request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
295 request_dict.SetString(kInstrumentIdKey, instrument_id);
296
297 std::string json_payload;
298 base::JSONWriter::Write(request_dict, &json_payload);
299
300 std::string escaped_card_verification_number = net::EscapeUrlEncodedData(
301 card_verification_number, true);
302
303 std::string post_body = base::StringPrintf(
304 kEscrowCardVerificationNumberFormat,
305 net::EscapeUrlEncodedData(json_payload, true).c_str(),
306 escaped_card_verification_number.c_str());
307
308 MakeWalletRequest(GetAuthenticateInstrumentUrl(user_index_),
309 post_body,
310 kFormEncodedMimeType,
311 AUTHENTICATE_INSTRUMENT);
312 }
313
314 void WalletClient::GetFullWallet(const FullWalletRequest& full_wallet_request) {
315 base::DictionaryValue request_dict;
316 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
317 request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
318 request_dict.SetBoolean(kUseMinimalAddresses, false);
319 request_dict.SetBoolean(kPhoneNumberRequired, true);
320 request_dict.SetBoolean(kNewWalletUser, full_wallet_request.new_wallet_user);
321
322 request_dict.SetString(kSelectedInstrumentIdKey,
323 full_wallet_request.instrument_id);
324 request_dict.SetString(kSelectedAddressIdKey, full_wallet_request.address_id);
325 request_dict.SetString(
326 kMerchantDomainKey,
327 source_url_.GetWithEmptyPath().spec());
328 request_dict.SetString(kGoogleTransactionIdKey,
329 full_wallet_request.google_transaction_id);
330 request_dict.SetString(kFeatureKey, "REQUEST_AUTOCOMPLETE");
331
332 scoped_ptr<base::ListValue> risk_capabilities_list(new base::ListValue());
333 for (std::vector<RiskCapability>::const_iterator it =
334 full_wallet_request.risk_capabilities.begin();
335 it != full_wallet_request.risk_capabilities.end();
336 ++it) {
337 risk_capabilities_list->AppendString(RiskCapabilityToString(*it));
338 }
339 request_dict.Set(kRiskCapabilitiesKey, risk_capabilities_list.release());
340
341 std::string json_payload;
342 base::JSONWriter::Write(request_dict, &json_payload);
343
344 crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
345
346 size_t num_bits = one_time_pad_.size() * 8;
347 DCHECK_LE(num_bits, kMaxBits);
348 DCHECK_GE(num_bits, kMinBits);
349
350 std::string post_body = base::StringPrintf(
351 kGetFullWalletRequestFormat,
352 net::EscapeUrlEncodedData(json_payload, true).c_str(),
353 base::HexEncode(&num_bits, 1).c_str(),
354 base::HexEncode(&(one_time_pad_[0]), one_time_pad_.size()).c_str());
355
356 MakeWalletRequest(GetGetFullWalletUrl(user_index_),
357 post_body,
358 kFormEncodedMimeType,
359 GET_FULL_WALLET);
360 }
361
362 void WalletClient::SaveToWallet(
363 scoped_ptr<Instrument> instrument,
364 scoped_ptr<Address> address,
365 const WalletItems::MaskedInstrument* reference_instrument,
366 const Address* reference_address) {
367 DCHECK(instrument || address);
368
369 base::DictionaryValue request_dict;
370 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
371 request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
372 request_dict.SetString(kMerchantDomainKey,
373 source_url_.GetWithEmptyPath().spec());
374 request_dict.SetBoolean(kUseMinimalAddresses, false);
375 request_dict.SetBoolean(kPhoneNumberRequired, true);
376
377 std::string primary_account_number;
378 std::string card_verification_number;
379 if (instrument) {
380 primary_account_number = net::EscapeUrlEncodedData(
381 base::UTF16ToUTF8(instrument->primary_account_number()), true);
382 card_verification_number = net::EscapeUrlEncodedData(
383 base::UTF16ToUTF8(instrument->card_verification_number()), true);
384
385 if (!reference_instrument) {
386 request_dict.Set(kInstrumentKey, instrument->ToDictionary().release());
387 request_dict.SetString(kInstrumentPhoneNumberKey,
388 instrument->address()->phone_number());
389 } else {
390 DCHECK(!reference_instrument->object_id().empty());
391
392 int new_month = instrument->expiration_month();
393 int new_year = instrument->expiration_year();
394 bool expiration_date_changed =
395 new_month != reference_instrument->expiration_month() ||
396 new_year != reference_instrument->expiration_year();
397
398 DCHECK(instrument->address() || expiration_date_changed);
399
400 request_dict.SetString(kUpgradedInstrumentIdKey,
401 reference_instrument->object_id());
402
403 if (instrument->address()) {
404 request_dict.SetString(kInstrumentPhoneNumberKey,
405 instrument->address()->phone_number());
406 request_dict.Set(
407 kUpgradedBillingAddressKey,
408 instrument->address()->ToDictionaryWithoutID().release());
409 }
410
411 if (expiration_date_changed) {
412 // Updating expiration date requires a CVC.
413 DCHECK(!instrument->card_verification_number().empty());
414 request_dict.SetInteger(kInstrumentExpMonthKey,
415 instrument->expiration_month());
416 request_dict.SetInteger(kInstrumentExpYearKey,
417 instrument->expiration_year());
418 }
419
420 if (request_dict.HasKey(kInstrumentKey))
421 request_dict.SetString(kInstrumentType, "CREDIT_CARD");
422 }
423 }
424 if (address) {
425 if (reference_address) {
426 address->set_object_id(reference_address->object_id());
427 DCHECK(!address->object_id().empty());
428 }
429 request_dict.Set(kShippingAddressKey,
430 address->ToDictionaryWithID().release());
431 }
432
433 std::string json_payload;
434 base::JSONWriter::Write(request_dict, &json_payload);
435
436 if (!card_verification_number.empty()) {
437 std::string post_body;
438 if (!primary_account_number.empty()) {
439 post_body = base::StringPrintf(
440 kEscrowNewInstrumentFormat,
441 net::EscapeUrlEncodedData(json_payload, true).c_str(),
442 card_verification_number.c_str(),
443 primary_account_number.c_str());
444 } else {
445 post_body = base::StringPrintf(
446 kEscrowCardVerificationNumberFormat,
447 net::EscapeUrlEncodedData(json_payload, true).c_str(),
448 card_verification_number.c_str());
449 }
450 MakeWalletRequest(GetSaveToWalletUrl(user_index_),
451 post_body,
452 kFormEncodedMimeType,
453 SAVE_TO_WALLET);
454 } else {
455 MakeWalletRequest(GetSaveToWalletNoEscrowUrl(user_index_),
456 json_payload,
457 kJsonMimeType,
458 SAVE_TO_WALLET);
459 }
460 }
461
462 void WalletClient::GetWalletItems(const base::string16& amount,
463 const base::string16& currency) {
464 base::DictionaryValue request_dict;
465 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
466 request_dict.SetString(kMerchantDomainKey,
467 source_url_.GetWithEmptyPath().spec());
468 request_dict.SetBoolean(kShippingAddressRequired,
469 delegate_->IsShippingAddressRequired());
470 request_dict.SetBoolean(kUseMinimalAddresses, false);
471 request_dict.SetBoolean(kPhoneNumberRequired, true);
472
473 if (!amount.empty())
474 request_dict.SetString(kTransactionAmountKey, amount);
475 if (!currency.empty())
476 request_dict.SetString(kTransactionCurrencyKey, currency);
477
478 std::string post_body;
479 base::JSONWriter::Write(request_dict, &post_body);
480
481 MakeWalletRequest(GetGetWalletItemsUrl(user_index_),
482 post_body,
483 kJsonMimeType,
484 GET_WALLET_ITEMS);
485 }
486
487 bool WalletClient::HasRequestInProgress() const {
488 return request_;
489 }
490
491 void WalletClient::CancelRequest() {
492 request_.reset();
493 request_type_ = NO_REQUEST;
494 }
495
496 void WalletClient::SetUserIndex(size_t user_index) {
497 CancelRequest();
498 user_index_ = user_index;
499 }
500
501 void WalletClient::DoAcceptLegalDocuments(
502 const std::vector<std::string>& document_ids,
503 const std::string& google_transaction_id) {
504 base::DictionaryValue request_dict;
505 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
506 request_dict.SetString(kGoogleTransactionIdKey, google_transaction_id);
507 request_dict.SetString(kMerchantDomainKey,
508 source_url_.GetWithEmptyPath().spec());
509 scoped_ptr<base::ListValue> docs_list(new base::ListValue());
510 for (std::vector<std::string>::const_iterator it = document_ids.begin();
511 it != document_ids.end(); ++it) {
512 if (!it->empty())
513 docs_list->AppendString(*it);
514 }
515 request_dict.Set(kAcceptedLegalDocumentKey, docs_list.release());
516
517 std::string post_body;
518 base::JSONWriter::Write(request_dict, &post_body);
519
520 MakeWalletRequest(GetAcceptLegalDocumentsUrl(user_index_),
521 post_body,
522 kJsonMimeType,
523 ACCEPT_LEGAL_DOCUMENTS);
524 }
525
526 void WalletClient::MakeWalletRequest(const GURL& url,
527 const std::string& post_body,
528 const std::string& mime_type,
529 RequestType request_type) {
530 DCHECK_EQ(request_type_, NO_REQUEST);
531 request_type_ = request_type;
532
533 request_ = net::URLFetcher::Create(0, url, net::URLFetcher::POST, this);
534 request_->SetRequestContext(context_getter_.get());
535 DVLOG(1) << "Making request to " << url << " with post_body=" << post_body;
536 request_->SetUploadData(mime_type, post_body);
537 request_->AddExtraRequestHeader("Authorization: GoogleLogin auth=" +
538 delegate_->GetWalletCookieValue());
539 DVLOG(1) << "Setting authorization header value to "
540 << delegate_->GetWalletCookieValue();
541 request_started_timestamp_ = base::Time::Now();
542 request_->Start();
543
544 AutofillMetrics::LogWalletErrorMetric(
545 AutofillMetrics::WALLET_ERROR_BASELINE_ISSUED_REQUEST);
546 AutofillMetrics::LogWalletRequiredActionMetric(
547 AutofillMetrics::WALLET_REQUIRED_ACTION_BASELINE_ISSUED_REQUEST);
548 }
549
550 // TODO(ahutter): Add manual retry logic if it's necessary.
551 void WalletClient::OnURLFetchComplete(
552 const net::URLFetcher* source) {
553 AutofillMetrics::LogWalletApiCallDuration(
554 RequestTypeToUmaMetric(request_type_),
555 base::Time::Now() - request_started_timestamp_);
556
557 DCHECK_EQ(source, request_.get());
558 DVLOG(1) << "Got response from " << source->GetOriginalURL();
559
560 // |request_|, which is aliased to |source|, might continue to be used in this
561 // |method, but should be freed once control leaves the method.
562 scoped_ptr<net::URLFetcher> scoped_request(request_.Pass());
563
564 std::string data;
565 source->GetResponseAsString(&data);
566 DVLOG(1) << "Response body: " << data;
567
568 scoped_ptr<base::DictionaryValue> response_dict;
569
570 int response_code = source->GetResponseCode();
571 AutofillMetrics::LogWalletResponseCode(response_code);
572
573 switch (response_code) {
574 // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
575 case net::HTTP_BAD_REQUEST: {
576 request_type_ = NO_REQUEST;
577 HandleWalletError(BAD_REQUEST);
578 return;
579 }
580
581 // Valid response.
582 case net::HTTP_OK: {
583 scoped_ptr<base::Value> message_value = base::JSONReader::Read(data);
584 if (message_value.get() &&
585 message_value->IsType(base::Value::TYPE_DICTIONARY)) {
586 response_dict.reset(
587 static_cast<base::DictionaryValue*>(message_value.release()));
588 }
589 break;
590 }
591
592 // Response contains an error to show the user.
593 case net::HTTP_FORBIDDEN:
594 case net::HTTP_INTERNAL_SERVER_ERROR: {
595 scoped_ptr<base::Value> message_value = base::JSONReader::Read(data);
596 if (message_value.get() &&
597 message_value->IsType(base::Value::TYPE_DICTIONARY)) {
598 response_dict.reset(
599 static_cast<base::DictionaryValue*>(message_value.release()));
600 }
601
602 request_type_ = NO_REQUEST;
603
604 std::string error_type_string;
605 if (!response_dict->GetString(kErrorTypeKey, &error_type_string)) {
606 HandleWalletError(UNKNOWN_ERROR);
607 return;
608 }
609 WalletClient::ErrorType error_type = StringToErrorType(error_type_string);
610 if (error_type == BUYER_ACCOUNT_ERROR) {
611 // If the error_type is |BUYER_ACCOUNT_ERROR|, then
612 // message_type_for_buyer field contains more specific information
613 // about the error.
614 std::string message_type_for_buyer_string;
615 if (response_dict->GetString(kMessageTypeForBuyerKey,
616 &message_type_for_buyer_string)) {
617 error_type =
618 BuyerErrorStringToErrorType(message_type_for_buyer_string);
619 }
620 }
621
622 HandleWalletError(error_type);
623 return;
624 }
625
626 // Handle anything else as a generic error.
627 default:
628 request_type_ = NO_REQUEST;
629 HandleWalletError(NETWORK_ERROR);
630 return;
631 }
632
633 RequestType type = request_type_;
634 request_type_ = NO_REQUEST;
635
636 if (type != ACCEPT_LEGAL_DOCUMENTS && !response_dict) {
637 HandleMalformedResponse(type, scoped_request.get());
638 return;
639 }
640
641 switch (type) {
642 case ACCEPT_LEGAL_DOCUMENTS:
643 delegate_->OnDidAcceptLegalDocuments();
644 break;
645
646 case AUTHENTICATE_INSTRUMENT: {
647 std::string auth_result;
648 if (response_dict->GetString(kAuthResultKey, &auth_result)) {
649 std::string trimmed;
650 base::TrimWhitespaceASCII(auth_result, base::TRIM_ALL, &trimmed);
651 delegate_->OnDidAuthenticateInstrument(
652 base::LowerCaseEqualsASCII(trimmed, "success"));
653 } else {
654 HandleMalformedResponse(type, scoped_request.get());
655 }
656 break;
657 }
658
659 case GET_FULL_WALLET: {
660 scoped_ptr<FullWallet> full_wallet(
661 FullWallet::CreateFullWallet(*response_dict));
662 if (full_wallet) {
663 full_wallet->set_one_time_pad(one_time_pad_);
664 LogRequiredActions(full_wallet->required_actions());
665 delegate_->OnDidGetFullWallet(full_wallet.Pass());
666 } else {
667 HandleMalformedResponse(type, scoped_request.get());
668 }
669 break;
670 }
671
672 case GET_WALLET_ITEMS: {
673 scoped_ptr<WalletItems> wallet_items(
674 WalletItems::CreateWalletItems(*response_dict));
675 if (wallet_items) {
676 LogRequiredActions(wallet_items->required_actions());
677 delegate_->OnDidGetWalletItems(wallet_items.Pass());
678 } else {
679 HandleMalformedResponse(type, scoped_request.get());
680 }
681 break;
682 }
683
684 case SAVE_TO_WALLET: {
685 std::string instrument_id;
686 response_dict->GetString(kInstrumentIdKey, &instrument_id);
687 std::string shipping_address_id;
688 response_dict->GetString(kShippingAddressIdKey,
689 &shipping_address_id);
690 std::vector<RequiredAction> required_actions;
691 GetRequiredActionsForSaveToWallet(*response_dict, &required_actions);
692 std::vector<FormFieldError> form_errors;
693 GetFormFieldErrors(*response_dict, &form_errors);
694 if (instrument_id.empty() && shipping_address_id.empty() &&
695 required_actions.empty()) {
696 HandleMalformedResponse(type, scoped_request.get());
697 } else {
698 LogRequiredActions(required_actions);
699 delegate_->OnDidSaveToWallet(instrument_id,
700 shipping_address_id,
701 required_actions,
702 form_errors);
703 }
704 break;
705 }
706
707 case NO_REQUEST:
708 NOTREACHED();
709 }
710 }
711
712 void WalletClient::HandleMalformedResponse(RequestType request_type,
713 net::URLFetcher* request) {
714 // Called to inform exponential backoff logic of the error.
715 request->ReceivedContentWasMalformed();
716 // Record failed API call in metrics.
717 AutofillMetrics::LogWalletMalformedResponseMetric(
718 RequestTypeToUmaMetric(request_type));
719 HandleWalletError(MALFORMED_RESPONSE);
720 }
721
722 void WalletClient::HandleWalletError(WalletClient::ErrorType error_type) {
723 std::string error_message;
724 switch (error_type) {
725 case WalletClient::BAD_REQUEST:
726 error_message = "WALLET_BAD_REQUEST";
727 break;
728 case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
729 error_message = "WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED";
730 break;
731 case WalletClient::BUYER_ACCOUNT_ERROR:
732 error_message = "WALLET_BUYER_ACCOUNT_ERROR";
733 break;
734 case WalletClient::INTERNAL_ERROR:
735 error_message = "WALLET_INTERNAL_ERROR";
736 break;
737 case WalletClient::INVALID_PARAMS:
738 error_message = "WALLET_INVALID_PARAMS";
739 break;
740 case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
741 error_message = "WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS";
742 break;
743 case WalletClient::SPENDING_LIMIT_EXCEEDED:
744 error_message = "SPENDING_LIMIT_EXCEEDED";
745 break;
746 case WalletClient::SERVICE_UNAVAILABLE:
747 error_message = "WALLET_SERVICE_UNAVAILABLE";
748 break;
749 case WalletClient::UNSUPPORTED_API_VERSION:
750 error_message = "WALLET_UNSUPPORTED_API_VERSION";
751 break;
752 case WalletClient::UNSUPPORTED_MERCHANT:
753 error_message = "WALLET_UNSUPPORTED_MERCHANT";
754 break;
755 case WalletClient::MALFORMED_RESPONSE:
756 error_message = "WALLET_MALFORMED_RESPONSE";
757 break;
758 case WalletClient::NETWORK_ERROR:
759 error_message = "WALLET_NETWORK_ERROR";
760 break;
761 case WalletClient::UNKNOWN_ERROR:
762 error_message = "WALLET_UNKNOWN_ERROR";
763 break;
764 case WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
765 error_message = "WALLET_UNSUPPORTED_USER_AGENT_OR_API_KEY";
766 break;
767 }
768
769 DVLOG(1) << "Wallet encountered a " << error_message;
770
771 delegate_->OnWalletError(error_type);
772 AutofillMetrics::LogWalletErrorMetric(ErrorTypeToUmaMetric(error_type));
773 }
774
775 // Logs an UMA metric for each of the |required_actions|.
776 void WalletClient::LogRequiredActions(
777 const std::vector<RequiredAction>& required_actions) const {
778 for (size_t i = 0; i < required_actions.size(); ++i) {
779 AutofillMetrics::LogWalletRequiredActionMetric(
780 RequiredActionToUmaMetric(required_actions[i]));
781 }
782 }
783
784 AutofillMetrics::WalletApiCallMetric WalletClient::RequestTypeToUmaMetric(
785 RequestType request_type) const {
786 switch (request_type) {
787 case ACCEPT_LEGAL_DOCUMENTS:
788 return AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS;
789 case AUTHENTICATE_INSTRUMENT:
790 return AutofillMetrics::AUTHENTICATE_INSTRUMENT;
791 case GET_FULL_WALLET:
792 return AutofillMetrics::GET_FULL_WALLET;
793 case GET_WALLET_ITEMS:
794 return AutofillMetrics::GET_WALLET_ITEMS;
795 case SAVE_TO_WALLET:
796 return AutofillMetrics::SAVE_TO_WALLET;
797 case NO_REQUEST:
798 NOTREACHED();
799 return AutofillMetrics::UNKNOWN_API_CALL;
800 }
801
802 NOTREACHED();
803 return AutofillMetrics::UNKNOWN_API_CALL;
804 }
805
806 } // namespace wallet
807 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698