OLD | NEW |
| (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 | |
OLD | NEW |