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

Side by Side Diff: chrome/browser/autofill/wallet/wallet_client.cc

Issue 11293078: Integrating Online Wallet into Chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixes from code review Created 8 years 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 | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/autofill/wallet/wallet_client.h"
6
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/string_number_conversions.h"
12 #include "base/string_split.h"
13 #include "base/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/browser/autofill/wallet/cart.h"
16 #include "chrome/browser/autofill/wallet/full_wallet.h"
17 #include "chrome/browser/autofill/wallet/wallet_address.h"
18 #include "chrome/browser/autofill/wallet/wallet_items.h"
19 #include "chrome/browser/autofill/wallet/wallet_service_url.h"
20 #include "googleurl/src/gurl.h"
21 #include "net/http/http_status_code.h"
22 #include "net/url_request/url_fetcher.h"
23 #include "net/url_request/url_fetcher_delegate.h"
24 #include "net/url_request/url_request_context_getter.h"
25
26 namespace {
27
28 const char kEncryptOtpBodyFormat[] = "cvv=%s:%s";
29 const char kJsonMimeType[] = "application/json";
30 const char kApplicationMimeType[] = "application/x-www-form-urlencoded";
31 const size_t kMaxBits = 63;
32
33 } // anonymous namespace
34
35 namespace wallet {
36
37 // TODO(ahutter): Add manual retry logic if it's necessary.
38 // The guts of WalletClient. Implements URLFetcherDelegate to actually make
39 // calls to the OnlineWallet API.
40 class WalletClient::Core
41 : public base::RefCountedThreadSafe<WalletClient::Core>,
42 public net::URLFetcherDelegate {
43 public:
44 explicit Core(net::URLRequestContextGetter* context_getter)
45 : context_getter_(context_getter),
46 observer_(NULL),
47 request_type_(NO_PENDING_REQUEST) {}
48 void AcceptLegalDocuments(const std::vector<std::string>& document_ids,
49 const std::string& google_transaction_id,
50 WalletClientObserver* observer);
51 void EncryptOtp(const void* otp,
52 size_t length,
53 WalletClientObserver* observer);
54 void GetFullWallet(const std::string& instrument_id,
55 const std::string& address_id,
56 const std::string& merchant_domain,
57 const Cart& cart,
58 const std::string& google_transaction_id,
59 const std::string& encrypted_otp,
60 const std::string& session_material,
61 WalletClientObserver* observer);
62 void GetWalletItems(WalletClientObserver* observer);
63 void SendExtendedAutofillStatus(bool success,
64 const std::string& merchant_domain,
65 const std::string& reason,
66 const std::string& google_transaction_id,
67 WalletClientObserver* observer);
68 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
69 private:
70 friend class base::RefCountedThreadSafe<Core>;
71 // TODO(ahutter): Implement this.
72 std::string GetRiskParams() { return ""; }
73
74 enum RequestType {
75 NO_PENDING_REQUEST,
76 ACCEPT_LEGAL_DOCUMENTS,
77 ENCRYPT_OTP,
78 GET_FULL_WALLET,
79 GET_WALLET_ITEMS,
80 SEND_STATUS,
81 };
82
83 virtual ~Core() {}
84
85 void MakeWalletRequest(const GURL& url,
86 const std::string& post_body,
87 WalletClient::WalletClientObserver* observer,
88 const std::string& content_type);
89
90 // The context for the request. Ensures the gdToken cookie is set as a header
91 // in the requests to Online Wallet if it is present.
92 scoped_refptr<net::URLRequestContextGetter> context_getter_;
93 // Observer class that has its various On* methods called based on the results
94 // of a request to Online Wallet.
95 WalletClient::WalletClientObserver* observer_;
96 // The current request object.
97 scoped_ptr<net::URLFetcher> request_;
98 // The type of the current request. Must be NO_PENDING_REQUEST for a request
99 // to be initiated as only one request may be running at a given time.
100 RequestType request_type_;
101 DISALLOW_COPY_AND_ASSIGN(Core);
102 };
103
104 void WalletClient::Core::AcceptLegalDocuments(
105 const std::vector<std::string>& document_ids,
106 const std::string& google_transaction_id,
107 WalletClient::WalletClientObserver* observer) {
108 DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
109
110 request_type_ = ACCEPT_LEGAL_DOCUMENTS;
111
112 DictionaryValue request_dict;
113 request_dict.SetString("api_key", wallet::kApiKey);
114 request_dict.SetString("google_transaction_id", google_transaction_id);
115 ListValue* docs_list = new ListValue();
116 for (std::vector<std::string>::const_iterator it = document_ids.begin();
117 it != document_ids.end();
118 ++it) {
119 docs_list->AppendString(*it);
120 }
121 request_dict.Set("accepted_legal_document", docs_list);
122
123 std::string post_body;
124 base::JSONWriter::Write(&request_dict, &post_body);
125
126 MakeWalletRequest(GetAcceptLegalDocumentsUrl(),
127 post_body,
128 observer,
129 kJsonMimeType);
130 }
131
132 void WalletClient::Core::EncryptOtp(
133 const void* otp,
134 size_t length,
135 WalletClient::WalletClientObserver* observer) {
136 DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
137 size_t num_bits = length * 8;
138 DCHECK_LT(num_bits, kMaxBits);
139
140 request_type_ = ENCRYPT_OTP;
141
142 std::string post_body = StringPrintf(kEncryptOtpBodyFormat,
143 base::HexEncode(&num_bits, 1).c_str(),
144 base::HexEncode(otp, length).c_str());
145
146 MakeWalletRequest(GetSecureUrl(), post_body, observer, kApplicationMimeType);
147 }
148
149 void WalletClient::Core::GetFullWallet(
150 const std::string& instrument_id,
151 const std::string& address_id,
152 const std::string& merchant_domain,
153 const Cart& cart,
154 const std::string& google_transaction_id,
155 const std::string& encrypted_otp,
156 const std::string& session_material,
157 WalletClient::WalletClientObserver* observer) {
158 DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
159
160 request_type_ = GET_FULL_WALLET;
161
162 DictionaryValue request_dict;
163 request_dict.SetString("api_key", wallet::kApiKey);
164 request_dict.SetString("risk_params", GetRiskParams());
165 request_dict.SetString("selected_instrument_id", instrument_id);
166 request_dict.SetString("selected_address_id", address_id);
167 request_dict.SetString("merchant_domain", merchant_domain);
168 request_dict.SetString("google_transaction_id", google_transaction_id);
169 request_dict.Set("cart", cart.ToDictionary().release());
170 request_dict.SetString("encrypted_otp", encrypted_otp);
171 request_dict.SetString("session_material", session_material);
172
173 std::string post_body;
174 base::JSONWriter::Write(&request_dict, &post_body);
175
176 MakeWalletRequest(GetGetFullWalletUrl(), post_body, observer, kJsonMimeType);
177 }
178
179 void WalletClient::Core::GetWalletItems(
180 WalletClient::WalletClientObserver* observer) {
181 DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
182
183 request_type_ = GET_WALLET_ITEMS;
184
185 DictionaryValue request_dict;
186 request_dict.SetString("api_key", wallet::kApiKey);
187 request_dict.SetString("risk_params", GetRiskParams());
188
189 std::string post_body;
190 base::JSONWriter::Write(&request_dict, &post_body);
191
192 MakeWalletRequest(GetGetWalletItemsUrl(), post_body, observer, kJsonMimeType);
193 }
194
195 void WalletClient::Core::SendExtendedAutofillStatus(
196 bool success,
197 const std::string& merchant_domain,
198 const std::string& reason,
199 const std::string& google_transaction_id,
200 WalletClient::WalletClientObserver* observer) {
201 DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
202
203 request_type_ = SEND_STATUS;
204
205 DictionaryValue request_dict;
206 request_dict.SetString("api_key", wallet::kApiKey);
207 request_dict.SetBoolean("success", success);
208 request_dict.SetString("hostname", merchant_domain);
209 if (!success) {
210 // TODO(ahutter): Probably want to do some checks on reason.
211 request_dict.SetString("reason", reason);
212 }
213 request_dict.SetString("google_transaction_id", google_transaction_id);
214
215 std::string post_body;
216 base::JSONWriter::Write(&request_dict, &post_body);
217
218 MakeWalletRequest(GetSendStatusUrl(), post_body, observer, kJsonMimeType);
219 }
220
221 void WalletClient::Core::MakeWalletRequest(
222 const GURL& url,
223 const std::string& post_body,
224 WalletClient::WalletClientObserver* observer,
225 const std::string& content_type) {
226 DCHECK(!request_.get()) << "Tried to fetch two things at once!";
227 DCHECK(observer);
228
229 observer_ = observer;
230
231 request_.reset(net::URLFetcher::Create(
232 0, url, net::URLFetcher::POST, this));
233 request_->SetRequestContext(context_getter_);
234 DVLOG(1) << "Request body: " << post_body;
235 request_->SetUploadData(content_type, post_body);
236 request_->Start();
237 }
238
239 void WalletClient::Core::OnURLFetchComplete(
240 const net::URLFetcher* source) {
241 scoped_ptr<net::URLFetcher> old_request = request_.Pass();
242 DCHECK_EQ(source, old_request.get());
243
244 DVLOG(1) << "Got response from " << source->GetOriginalURL();
245
246 std::string data;
247 scoped_ptr<DictionaryValue> response_dict;
248 int response_code = source->GetResponseCode();
249 switch (response_code) {
250 // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
251 case net::HTTP_BAD_REQUEST: {
252 request_type_ = NO_PENDING_REQUEST;
253 observer_->OnWalletError();
254 return;
255 }
256 // HTTP_OK holds a valid response and HTTP_INTERNAL_SERVER_ERROR holds an
257 // error code and message for the user.
258 case net::HTTP_OK:
259 case net::HTTP_INTERNAL_SERVER_ERROR: {
260 source->GetResponseAsString(&data);
261 DVLOG(1) << "Response body: " << data;
262 scoped_ptr<Value> message_value(base::JSONReader::Read(data));
263 if (message_value.get() &&
264 message_value->IsType(Value::TYPE_DICTIONARY)) {
265 response_dict.reset(
266 static_cast<DictionaryValue*>(message_value.release()));
267 }
268 if (response_code == net::HTTP_INTERNAL_SERVER_ERROR) {
269 request_type_ = NO_PENDING_REQUEST;
270 // TODO(ahutter): Do something with the response. See
271 // http://crbug.com/164410.
272 observer_->OnWalletError();
273 return;
274 }
275 break;
276 }
277 // Anything else is an error.
278 default: {
279 request_type_ = NO_PENDING_REQUEST;
280 observer_->OnNetworkError(response_code);
281 return;
282 }
283 }
284
285 RequestType type = request_type_;
286 request_type_ = NO_PENDING_REQUEST;
287
288 switch (type) {
289 case ACCEPT_LEGAL_DOCUMENTS: {
290 observer_->OnAcceptLegalDocuments();
291 break;
292 }
293 case SEND_STATUS: {
294 observer_->OnSendExtendedAutofillStatus();
295 break;
296 }
297 case ENCRYPT_OTP: {
298 if (!data.empty()) {
299 std::vector<std::string> splits;
300 base::SplitString(data, '|', &splits);
301 if (splits.size() == 2)
302 observer_->OnEncryptOtp(splits[1], splits[0]);
303 else
304 observer_->OnNetworkError(response_code);
305 } else {
306 observer_->OnWalletError();
307 }
308 break;
309 }
310 case GET_FULL_WALLET: {
311 if (response_dict.get()) {
312 scoped_ptr<FullWallet> full_wallet(
313 FullWallet::CreateFullWallet(*response_dict));
314 if (full_wallet.get())
315 observer_->OnGetFullWallet(full_wallet.release());
316 else
317 observer_->OnNetworkError(response_code);
318 } else {
319 observer_->OnWalletError();
320 }
321 break;
322 }
323 case GET_WALLET_ITEMS: {
324 if (response_dict.get()) {
325 scoped_ptr<WalletItems> wallet_items(
326 WalletItems::CreateWalletItems(*response_dict));
327 if (wallet_items.get())
328 observer_->OnGetWalletItems(wallet_items.release());
329 else
330 observer_->OnNetworkError(response_code);
331 } else {
332 observer_->OnWalletError();
333 }
334 break;
335 }
336 default: {
337 NOTREACHED();
338 }
339 }
340 }
341
342 WalletClient::WalletClient(
343 net::URLRequestContextGetter* context_getter) {
344 DCHECK(context_getter);
345
346 core_ = new Core(context_getter);
347 }
348
349 WalletClient::~WalletClient() {}
350
351 void WalletClient::GetWalletItems(
352 WalletClient::WalletClientObserver* observer) {
353 core_->GetWalletItems(observer);
354 }
355
356 void WalletClient::AcceptLegalDocuments(
357 const std::vector<std::string>& document_ids,
358 const std::string& google_transaction_id,
359 WalletClient::WalletClientObserver* observer) {
360 core_->AcceptLegalDocuments(document_ids,
361 google_transaction_id,
362 observer);
363 }
364
365 void WalletClient::EncryptOtp(
366 const void* otp,
367 size_t length,
368 WalletClient::WalletClientObserver* observer) {
369 core_->EncryptOtp(otp, length, observer);
370 }
371
372 void WalletClient::GetFullWallet(
373 const std::string& instrument_id,
374 const std::string& address_id,
375 const std::string& merchant_domain,
376 const Cart& cart,
377 const std::string& google_transaction_id,
378 const std::string& encrypted_otp,
379 const std::string& session_material,
380 WalletClient::WalletClientObserver* observer) {
381 core_->GetFullWallet(instrument_id,
382 address_id,
383 merchant_domain,
384 cart,
385 google_transaction_id,
386 encrypted_otp,
387 session_material,
388 observer);
389 }
390
391 void WalletClient::SendExtendedAutofillStatus(
392 bool success,
393 const std::string& merchant_domain,
394 const std::string& reason,
395 const std::string& google_transaction_id,
396 WalletClient::WalletClientObserver* observer) {
397 core_->SendExtendedAutofillStatus(success,
398 merchant_domain,
399 reason,
400 google_transaction_id,
401 observer);
402 }
403
404 } // namespace wallet
405
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698