| Index: chrome/browser/autofill/wallet/wallet_data_retriever.cc
|
| diff --git a/chrome/browser/autofill/wallet/wallet_data_retriever.cc b/chrome/browser/autofill/wallet/wallet_data_retriever.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f281bb11816033270b017afa2c1ea0a24ed5f5f3
|
| --- /dev/null
|
| +++ b/chrome/browser/autofill/wallet/wallet_data_retriever.cc
|
| @@ -0,0 +1,378 @@
|
| +// 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/autofill/wallet/wallet_data_retriever.h"
|
| +
|
| +#include "base/json/json_reader.h"
|
| +#include "base/json/json_writer.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/string_number_conversions.h"
|
| +#include "base/string_split.h"
|
| +#include "base/stringprintf.h"
|
| +#include "base/values.h"
|
| +#include "chrome/browser/autofill/wallet/cart.h"
|
| +#include "chrome/browser/autofill/wallet/full_wallet.h"
|
| +#include "chrome/browser/autofill/wallet/wallet_address.h"
|
| +#include "chrome/browser/autofill/wallet/wallet_items.h"
|
| +#include "chrome/browser/autofill/wallet/wallet_service_url.h"
|
| +#include "googleurl/src/gurl.h"
|
| +#include "net/http/http_status_code.h"
|
| +#include "net/url_request/url_fetcher.h"
|
| +#include "net/url_request/url_fetcher_delegate.h"
|
| +#include "net/url_request/url_request_context_getter.h"
|
| +
|
| +namespace {
|
| +static const char kEncryptOtpBodyFormat[] = "cvv=%s:%s";
|
| +static const size_t kMaxBits = 63;
|
| +
|
| +} // end anonymous namespace
|
| +
|
| +namespace wallet {
|
| +
|
| +class WalletDataRetriever::Core
|
| + : public base::RefCountedThreadSafe<WalletDataRetriever::Core>,
|
| + public net::URLFetcherDelegate {
|
| + public:
|
| + explicit Core(net::URLRequestContextGetter* context_getter)
|
| + : context_getter_(context_getter),
|
| + delegate_(NULL),
|
| + request_type_(NO_PENDING_REQUEST) {}
|
| + void AcceptLegalDocuments(const std::vector<std::string> document_ids,
|
| + const std::string& google_transaction_id,
|
| + Delegate* delegate);
|
| + void EncryptOtp(const void* otp, size_t length, Delegate* delegate);
|
| + void GetFullWallet(const std::string& instrument_id,
|
| + const std::string& address_id,
|
| + const std::string& merchant_domain,
|
| + const Cart& cart,
|
| + const std::string& google_transaction_id,
|
| + const std::string& encrypted_otp,
|
| + const std::string& session_material,
|
| + Delegate* delegate);
|
| + void GetWalletItems(Delegate* delegate);
|
| + void SendExtendedAutofillStatus(bool success,
|
| + const std::string& merchant_domain,
|
| + const std::string& reason,
|
| + const std::string& google_transaction_id,
|
| + Delegate* delegate);
|
| + virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
|
| + private:
|
| + friend class base::RefCountedThreadSafe<Core>;
|
| + std::string GetRiskParams() { return ""; }
|
| +
|
| + enum RequestType {
|
| + NO_PENDING_REQUEST,
|
| + ACCEPT_LEGAL_DOCUMENTS,
|
| + ENCRYPT_OTP,
|
| + GET_FULL_WALLET,
|
| + GET_WALLET_ITEMS,
|
| + SEND_STATUS,
|
| + };
|
| +
|
| + virtual ~Core() {}
|
| +
|
| + void MakeWalletRequest(const GURL url,
|
| + const std::string& post_body,
|
| + WalletDataRetriever::Delegate* delegate,
|
| + const std::string& content_type = "application/json");
|
| +
|
| + void HandleResponse(const net::URLFetcher* source,
|
| + bool* should_retry_request);
|
| +
|
| + scoped_refptr<net::URLRequestContextGetter> context_getter_;
|
| + WalletDataRetriever::Delegate* delegate_;
|
| + scoped_ptr<net::URLFetcher> request_;
|
| + RequestType request_type_;
|
| +};
|
| +
|
| +void WalletDataRetriever::Core::AcceptLegalDocuments(
|
| + const std::vector<std::string> document_ids,
|
| + const std::string& google_transaction_id,
|
| + WalletDataRetriever::Delegate* delegate) {
|
| + DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
|
| + request_type_ = ACCEPT_LEGAL_DOCUMENTS;
|
| + GURL url = GetAcceptLegalDocumentsUrl();
|
| + DictionaryValue request_dict;
|
| + request_dict.SetString("api_key", wallet::kApiKey);
|
| + request_dict.SetString("google_transaction_id", google_transaction_id);
|
| + ListValue* docs_list = new ListValue();
|
| + for (std::vector<std::string>::const_iterator it = document_ids.begin();
|
| + it != document_ids.end();
|
| + ++it)
|
| + docs_list->AppendString(*it);
|
| + request_dict.Set("accepted_legal_document", docs_list);
|
| +
|
| + std::string post_body;
|
| + base::JSONWriter::Write(&request_dict, &post_body);
|
| + MakeWalletRequest(url, post_body, delegate);
|
| +}
|
| +
|
| +void WalletDataRetriever::Core::EncryptOtp(
|
| + const void* otp,
|
| + size_t length,
|
| + WalletDataRetriever::Delegate* delegate) {
|
| + DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
|
| + request_type_ = ENCRYPT_OTP;
|
| + GURL url = GetSecureUrl();
|
| + size_t num_bits = length * 8;
|
| + CHECK_LT(num_bits, kMaxBits);
|
| + std::string post_body = StringPrintf(kEncryptOtpBodyFormat,
|
| + base::HexEncode(&num_bits, 1).c_str(),
|
| + base::HexEncode(otp, length).c_str());
|
| + MakeWalletRequest(url,
|
| + post_body,
|
| + delegate,
|
| + "application/x-www-form-urlencoded");
|
| +}
|
| +
|
| +void WalletDataRetriever::Core::GetFullWallet(
|
| + const std::string& instrument_id,
|
| + const std::string& address_id,
|
| + const std::string& merchant_domain,
|
| + const Cart& cart,
|
| + const std::string& google_transaction_id,
|
| + const std::string& encrypted_otp,
|
| + const std::string& session_material,
|
| + WalletDataRetriever::Delegate* delegate) {
|
| + DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
|
| + request_type_ = GET_FULL_WALLET;
|
| + GURL url = GetGetFullWalletUrl();
|
| + DictionaryValue request_dict;
|
| + request_dict.SetString("api_key", wallet::kApiKey);
|
| + request_dict.SetString("risk_params", GetRiskParams());
|
| + request_dict.SetString("selected_instrument_id", instrument_id);
|
| + request_dict.SetString("selected_address_id", address_id);
|
| + request_dict.SetString("merchant_domain", merchant_domain);
|
| + request_dict.SetString("google_transaction_id", google_transaction_id);
|
| + scoped_ptr<DictionaryValue> cart_dict = cart.ToDictionary();
|
| + request_dict.Set("cart", cart_dict.release());
|
| + request_dict.SetString("encrypted_otp", encrypted_otp);
|
| + request_dict.SetString("session_material", session_material);
|
| + std::string post_body;
|
| + base::JSONWriter::Write(&request_dict, &post_body);
|
| + MakeWalletRequest(url, post_body, delegate);
|
| +}
|
| +
|
| +void WalletDataRetriever::Core::GetWalletItems(
|
| + WalletDataRetriever::Delegate* delegate) {
|
| + DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
|
| + request_type_ = GET_WALLET_ITEMS;
|
| + GURL url = GetGetWalletItemsUrl();
|
| + DictionaryValue request_dict;
|
| + request_dict.SetString("api_key", wallet::kApiKey);
|
| + request_dict.SetString("risk_params", GetRiskParams());
|
| + std::string post_body;
|
| + base::JSONWriter::Write(&request_dict, &post_body);
|
| + MakeWalletRequest(url, post_body, delegate);
|
| +}
|
| +
|
| +void WalletDataRetriever::Core::SendExtendedAutofillStatus(
|
| + bool success,
|
| + const std::string& merchant_domain,
|
| + const std::string& reason,
|
| + const std::string& google_transaction_id,
|
| + WalletDataRetriever::Delegate* delegate) {
|
| + DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
|
| + request_type_ = SEND_STATUS;
|
| + GURL url = GetSendStatusUrl();
|
| + DictionaryValue request_dict;
|
| + request_dict.SetString("api_key", wallet::kApiKey);
|
| + request_dict.SetBoolean("success", success);
|
| + request_dict.SetString("hostname", merchant_domain);
|
| + if (!success)
|
| + // TODO(ahutter): Probably want to do some checks on reason
|
| + request_dict.SetString("reason", reason);
|
| + request_dict.SetString("google_transaction_id", google_transaction_id);
|
| + std::string post_body;
|
| + base::JSONWriter::Write(&request_dict, &post_body);
|
| + MakeWalletRequest(url, post_body, delegate);
|
| +}
|
| +
|
| +void WalletDataRetriever::Core::MakeWalletRequest(
|
| + GURL url,
|
| + const std::string& post_body,
|
| + WalletDataRetriever::Delegate* delegate,
|
| + const std::string& content_type) {
|
| + DCHECK(!request_.get()) << "Tried to fetch two things at once!";
|
| + delegate_ = delegate;
|
| + request_.reset(net::URLFetcher::Create(
|
| + 0, url, net::URLFetcher::POST, this));
|
| + request_->SetRequestContext(context_getter_);
|
| + VLOG(1) << "Request body: " << post_body;
|
| + request_->SetUploadData(content_type, post_body);
|
| + request_->SetMaxRetries(0);
|
| + request_->Start();
|
| +}
|
| +
|
| +
|
| +void WalletDataRetriever::Core::OnURLFetchComplete(
|
| + const net::URLFetcher* source) {
|
| + bool should_retry = false;
|
| + HandleResponse(source, &should_retry);
|
| + if (should_retry) {
|
| + // Explicitly call ReceivedContentWasMalformed() to ensure the current
|
| + // request gets counted as a failure for calculation of the back-off
|
| + // period. If it was already a failure by status code, this call will
|
| + // be ignored.
|
| + request_->ReceivedContentWasMalformed();
|
| + // We must set our context_getter_ again because
|
| + // URLFetcher::Core::RetryOrCompleteUrlFetch resets it to NULL...
|
| + request_->SetRequestContext(context_getter_);
|
| + request_->Start();
|
| + }
|
| +}
|
| +
|
| +void WalletDataRetriever::Core::HandleResponse(
|
| + const net::URLFetcher* source,
|
| + bool* should_retry_request) {
|
| + // Keep the URLFetcher object in case we need to reuse it.
|
| + scoped_ptr<net::URLFetcher> old_request = request_.Pass();
|
| + DCHECK_EQ(source, old_request.get());
|
| +
|
| + // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying. We are
|
| + // done here.
|
| + if (source->GetResponseCode() == net::HTTP_BAD_REQUEST) {
|
| + request_type_ = NO_PENDING_REQUEST;
|
| + delegate_->OnWalletError();
|
| + return;
|
| + }
|
| +
|
| + scoped_ptr<DictionaryValue> response_dict;
|
| + if (source->GetResponseCode() == net::HTTP_OK) {
|
| + std::string data;
|
| + source->GetResponseAsString(&data);
|
| + VLOG(1) << "Response body: " << data;
|
| + scoped_ptr<Value> message_value(base::JSONReader::Read(data));
|
| + if (message_value.get() &&
|
| + message_value->IsType(Value::TYPE_DICTIONARY)) {
|
| + response_dict.reset(
|
| + static_cast<DictionaryValue*>(message_value.release()));
|
| + }
|
| + }
|
| +
|
| + // TODO(ahutter): this condition sucks. needs to be simplified.
|
| + if (!response_dict.get() &&
|
| + (!(request_type_ == SEND_STATUS
|
| + || request_type_ == ACCEPT_LEGAL_DOCUMENTS
|
| + || request_type_ == ENCRYPT_OTP)
|
| + || source->GetResponseCode() != net::HTTP_OK)) {
|
| + if ((source->GetMaxRetries() != -1)) {
|
| + request_type_ = NO_PENDING_REQUEST;
|
| + VLOG(1) << "Hitting " << source->GetOriginalURL();
|
| + delegate_->OnNetworkError(source->GetResponseCode());
|
| + } else {
|
| + request_ = old_request.Pass();
|
| + *should_retry_request = true;
|
| + }
|
| + return;
|
| + }
|
| +
|
| + RequestType type = request_type_;
|
| + request_type_ = NO_PENDING_REQUEST;
|
| +
|
| + switch (type) {
|
| + case ACCEPT_LEGAL_DOCUMENTS:
|
| + delegate_->OnAcceptLegalDocuments();
|
| + break;
|
| + case ENCRYPT_OTP: {
|
| + std::string data;
|
| + source->GetResponseAsString(&data);
|
| + std::vector<std::string> splits;
|
| + base::SplitString(data, '|', &splits);
|
| + if (splits.size() != 2) {
|
| + delegate_->OnWalletError();
|
| + } else {
|
| + delegate_->OnEncryptOtp(splits[1], splits[0]);
|
| + }
|
| + break;
|
| + }
|
| + case SEND_STATUS:
|
| + delegate_->OnSendExtendedAutofillStatus();
|
| + break;
|
| + case GET_FULL_WALLET: {
|
| + scoped_ptr<FullWallet> full_wallet =
|
| + FullWallet::FromDictionary(response_dict.get());
|
| + if (full_wallet.get()) {
|
| + delegate_->OnGetFullWallet(full_wallet.release());
|
| + } else {
|
| + delegate_->OnWalletError();
|
| + }
|
| + break;
|
| + }
|
| + case GET_WALLET_ITEMS: {
|
| + scoped_ptr<WalletItems> wallet_items =
|
| + WalletItems::FromDictionary(response_dict.get());
|
| + if (wallet_items.get()) {
|
| + delegate_->OnGetWalletItems(wallet_items.release());
|
| + } else {
|
| + delegate_->OnWalletError();
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| +}
|
| +
|
| +WalletDataRetriever::WalletDataRetriever(
|
| + net::URLRequestContextGetter* context_getter) {
|
| + core_ = new Core(context_getter);
|
| +}
|
| +
|
| +WalletDataRetriever::~WalletDataRetriever() {}
|
| +
|
| +void WalletDataRetriever::AcceptLegalDocuments(
|
| + const std::vector<std::string> document_ids,
|
| + const std::string& google_transaction_id,
|
| + WalletDataRetriever::Delegate* delegate) {
|
| + core_->AcceptLegalDocuments(document_ids,
|
| + google_transaction_id,
|
| + delegate);
|
| +}
|
| +
|
| +void WalletDataRetriever::EncryptOtp(const void* otp,
|
| + size_t length,
|
| + WalletDataRetriever::Delegate* delegate) {
|
| + core_->EncryptOtp(otp, length, delegate);
|
| +}
|
| +
|
| +void WalletDataRetriever::GetFullWallet(
|
| + const std::string& instrument_id,
|
| + const std::string& address_id,
|
| + const std::string& merchant_domain,
|
| + const Cart& cart,
|
| + const std::string& google_transaction_id,
|
| + const std::string& encrypted_otp,
|
| + const std::string& session_material,
|
| + WalletDataRetriever::Delegate* delegate) {
|
| + core_->GetFullWallet(instrument_id,
|
| + address_id,
|
| + merchant_domain,
|
| + cart,
|
| + google_transaction_id,
|
| + encrypted_otp,
|
| + session_material,
|
| + delegate);
|
| +}
|
| +
|
| +void WalletDataRetriever::GetWalletItems(
|
| + WalletDataRetriever::Delegate* delegate) {
|
| + core_->GetWalletItems(delegate);
|
| +}
|
| +
|
| +void WalletDataRetriever::SendExtendedAutofillStatus(
|
| + bool success,
|
| + const std::string& merchant_domain,
|
| + const std::string& reason,
|
| + const std::string& google_transaction_id,
|
| + WalletDataRetriever::Delegate* delegate) {
|
| + core_->SendExtendedAutofillStatus(success,
|
| + merchant_domain,
|
| + reason,
|
| + google_transaction_id,
|
| + delegate);
|
| +}
|
| +
|
| +} // end wallet namespace
|
|
|