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

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 latest 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 } // end anonymous namespace
34
35 namespace wallet {
36
37 class WalletClient::Core
38 : public base::RefCountedThreadSafe<WalletClient::Core>,
39 public net::URLFetcherDelegate {
40 public:
41 explicit Core(net::URLRequestContextGetter* context_getter)
42 : context_getter_(context_getter),
43 observer_(NULL),
44 request_type_(NO_PENDING_REQUEST),
45 num_retries_(0) {}
46 void AcceptLegalDocuments(const std::vector<std::string>& document_ids,
47 const std::string& google_transaction_id,
48 WalletClientObserver* observer);
49 void EncryptOtp(const void* otp,
50 size_t length,
51 WalletClientObserver* observer);
52 void GetFullWallet(const std::string& instrument_id,
53 const std::string& address_id,
54 const std::string& merchant_domain,
55 const Cart& cart,
56 const std::string& google_transaction_id,
57 const std::string& encrypted_otp,
58 const std::string& session_material,
59 WalletClientObserver* observer);
60 void GetWalletItems(WalletClientObserver* observer);
61 void SendExtendedAutofillStatus(bool success,
62 const std::string& merchant_domain,
63 const std::string& reason,
64 const std::string& google_transaction_id,
65 WalletClientObserver* observer);
66 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
67 private:
68 friend class base::RefCountedThreadSafe<Core>;
69 // TODO(ahutter): Implement this.
70 std::string GetRiskParams() { return ""; }
71
72 enum RequestType {
73 NO_PENDING_REQUEST,
74 ACCEPT_LEGAL_DOCUMENTS,
75 ENCRYPT_OTP,
76 GET_FULL_WALLET,
77 GET_WALLET_ITEMS,
78 SEND_STATUS,
79 };
80
81 virtual ~Core() {}
82
83 void MakeWalletRequest(const GURL url,
84 const std::string& post_body,
85 WalletClient::WalletClientObserver* observer,
86 const std::string& content_type);
87
88 void HandleResponse(const net::URLFetcher* source,
89 bool* should_retry_request);
90
91 void MaybeRetry(scoped_ptr<net::URLFetcher>* old_request,
92 const net::URLFetcher* source,
93 bool* should_retry_request);
94
95 scoped_refptr<net::URLRequestContextGetter> context_getter_;
96 WalletClient::WalletClientObserver* observer_;
97 scoped_ptr<net::URLFetcher> request_;
98 RequestType request_type_;
99 int num_retries_;
100 DISALLOW_COPY_AND_ASSIGN(Core);
101 };
102
103 void WalletClient::Core::AcceptLegalDocuments(
104 const std::vector<std::string>& document_ids,
105 const std::string& google_transaction_id,
106 WalletClient::WalletClientObserver* observer) {
107 DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
108 request_type_ = ACCEPT_LEGAL_DOCUMENTS;
109 GURL url = GetAcceptLegalDocumentsUrl();
110 DictionaryValue request_dict;
111 request_dict.SetString("api_key", wallet::kApiKey);
112 request_dict.SetString("google_transaction_id", google_transaction_id);
113 ListValue* docs_list = new ListValue();
114 for (std::vector<std::string>::const_iterator it = document_ids.begin();
115 it != document_ids.end();
116 ++it) {
117 docs_list->AppendString(*it);
118 }
119 request_dict.Set("accepted_legal_document", docs_list);
120
121 std::string post_body;
122 base::JSONWriter::Write(&request_dict, &post_body);
123 MakeWalletRequest(url, post_body, observer, kJsonMimeType);
124 }
125
126 void WalletClient::Core::EncryptOtp(
127 const void* otp,
128 size_t length,
129 WalletClient::WalletClientObserver* observer) {
130 DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
131 request_type_ = ENCRYPT_OTP;
132 GURL url = GetSecureUrl();
133 size_t num_bits = length * 8;
134 DCHECK_LT(num_bits, kMaxBits);
135 std::string post_body = StringPrintf(kEncryptOtpBodyFormat,
136 base::HexEncode(&num_bits, 1).c_str(),
137 base::HexEncode(otp, length).c_str());
138 MakeWalletRequest(url, post_body, observer, kApplicationMimeType);
139 }
140
141 void WalletClient::Core::GetFullWallet(
142 const std::string& instrument_id,
143 const std::string& address_id,
144 const std::string& merchant_domain,
145 const Cart& cart,
146 const std::string& google_transaction_id,
147 const std::string& encrypted_otp,
148 const std::string& session_material,
149 WalletClient::WalletClientObserver* observer) {
150 DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
151 request_type_ = GET_FULL_WALLET;
152 GURL url = GetGetFullWalletUrl();
153 DictionaryValue request_dict;
154 request_dict.SetString("api_key", wallet::kApiKey);
155 request_dict.SetString("risk_params", GetRiskParams());
156 request_dict.SetString("selected_instrument_id", instrument_id);
157 request_dict.SetString("selected_address_id", address_id);
158 request_dict.SetString("merchant_domain", merchant_domain);
159 request_dict.SetString("google_transaction_id", google_transaction_id);
160 request_dict.Set("cart", cart.ToDictionary().release());
161 request_dict.SetString("encrypted_otp", encrypted_otp);
162 request_dict.SetString("session_material", session_material);
163 std::string post_body;
164 base::JSONWriter::Write(&request_dict, &post_body);
165 MakeWalletRequest(url, post_body, observer, kJsonMimeType);
166 }
167
168 void WalletClient::Core::GetWalletItems(
169 WalletClient::WalletClientObserver* observer) {
170 DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
171 request_type_ = GET_WALLET_ITEMS;
172 GURL url = GetGetWalletItemsUrl();
173 DictionaryValue request_dict;
174 request_dict.SetString("api_key", wallet::kApiKey);
175 request_dict.SetString("risk_params", GetRiskParams());
176 std::string post_body;
177 base::JSONWriter::Write(&request_dict, &post_body);
178 MakeWalletRequest(url, post_body, observer, kJsonMimeType);
179 }
180
181 void WalletClient::Core::SendExtendedAutofillStatus(
182 bool success,
183 const std::string& merchant_domain,
184 const std::string& reason,
185 const std::string& google_transaction_id,
186 WalletClient::WalletClientObserver* observer) {
187 DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
188 request_type_ = SEND_STATUS;
189 GURL url = GetSendStatusUrl();
190 DictionaryValue request_dict;
191 request_dict.SetString("api_key", wallet::kApiKey);
192 request_dict.SetBoolean("success", success);
193 request_dict.SetString("hostname", merchant_domain);
194 if (!success) {
195 // TODO(ahutter): Probably want to do some checks on reason.
196 request_dict.SetString("reason", reason);
197 }
198 request_dict.SetString("google_transaction_id", google_transaction_id);
199 std::string post_body;
200 base::JSONWriter::Write(&request_dict, &post_body);
201 MakeWalletRequest(url, post_body, observer, kJsonMimeType);
202 }
203
204 void WalletClient::Core::MakeWalletRequest(
205 GURL url,
206 const std::string& post_body,
207 WalletClient::WalletClientObserver* observer,
208 const std::string& content_type) {
209 DCHECK(!request_.get()) << "Tried to fetch two things at once!";
210 DCHECK(observer);
211 num_retries_ = 0;
212 observer_ = observer;
213 request_.reset(net::URLFetcher::Create(
214 0, url, net::URLFetcher::POST, this));
215 request_->SetRequestContext(context_getter_);
216 DVLOG(1) << "Request body: " << post_body;
217 request_->SetUploadData(content_type, post_body);
218 request_->SetMaxRetries(3);
219 request_->Start();
220 }
221
222
223 void WalletClient::Core::OnURLFetchComplete(
224 const net::URLFetcher* source) {
225 bool should_retry;
226 HandleResponse(source, &should_retry);
227 if (should_retry) {
228 // Explicitly call ReceivedContentWasMalformed() to ensure the current
229 // request gets counted as a failure for calculation of the back-off
230 // period. If it was already a failure by status code, this call will
231 // be ignored.
232 request_->ReceivedContentWasMalformed();
233 num_retries_++;
234 // Set context_getter_ again because
235 // URLFetcher::Core::RetryOrCompleteUrlFetch resets it to NULL.
236 request_->SetRequestContext(context_getter_);
237 request_->Start();
238 }
239 }
240
241 void WalletClient::Core::MaybeRetry(
242 scoped_ptr<net::URLFetcher>* old_request,
243 const net::URLFetcher* source,
244 bool* should_retry_request) {
245 if (source->GetMaxRetries() != -1 &&
246 num_retries_ >= source->GetMaxRetries()) {
247 request_type_ = NO_PENDING_REQUEST;
248 observer_->OnNetworkError(source->GetResponseCode());
249 } else {
250 request_ = old_request->Pass();
251 *should_retry_request = true;
252 }
253 }
254
255 void WalletClient::Core::HandleResponse(
256 const net::URLFetcher* source,
257 bool* should_retry_request) {
258 // Keep the URLFetcher object in case we need to reuse it.
259 scoped_ptr<net::URLFetcher> old_request = request_.Pass();
260 DCHECK_EQ(source, old_request.get());
261 *should_retry_request = false;
262
263 DVLOG(1) << "Got response from " << source->GetOriginalURL();
264
265 int response_code = source->GetResponseCode();
266 std::string data;
267 scoped_ptr<DictionaryValue> response_dict;
268 switch (response_code) {
269 // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
270 case net::HTTP_BAD_REQUEST: {
271 request_type_ = NO_PENDING_REQUEST;
272 observer_->OnWalletError();
273 return;
274 }
275 // HTTP_OK holds a valid response and HTTP_INTERNAL_SERVER_ERROR holds an
276 // error code and message for the user.
277 case net::HTTP_OK:
278 case net::HTTP_INTERNAL_SERVER_ERROR: {
279 source->GetResponseAsString(&data);
280 DVLOG(1) << "Response body: " << data;
281 scoped_ptr<Value> message_value(base::JSONReader::Read(data));
282 if (message_value.get() &&
283 message_value->IsType(Value::TYPE_DICTIONARY)) {
284 response_dict.reset(
285 static_cast<DictionaryValue*>(message_value.release()));
286 }
287 if (response_code == net::HTTP_INTERNAL_SERVER_ERROR) {
288 request_type_ = NO_PENDING_REQUEST;
289 // TODO(ahutter): Do something with the response. See
290 // http://crbug.com/164410.
291 observer_->OnWalletError();
292 return;
293 }
294 break;
295 }
296 // Anything else is an error.
297 default: {
298 MaybeRetry(&old_request, source, should_retry_request);
299 return;
300 }
301 }
302
303 RequestType type = request_type_;
304 request_type_ = NO_PENDING_REQUEST;
305
306 switch (type) {
307 case ACCEPT_LEGAL_DOCUMENTS: {
308 observer_->OnAcceptLegalDocuments();
309 break;
310 }
311 case SEND_STATUS: {
312 observer_->OnSendExtendedAutofillStatus();
313 break;
314 }
315 case ENCRYPT_OTP: {
316 if (!data.empty()) {
317 std::vector<std::string> splits;
318 base::SplitString(data, '|', &splits);
319 if (splits.size() == 2)
320 observer_->OnEncryptOtp(splits[1], splits[0]);
321 else
322 observer_->OnNetworkError(response_code);
323 } else {
324 MaybeRetry(&old_request, source, should_retry_request);
325 }
326 break;
327 }
328 case GET_FULL_WALLET: {
329 if (response_dict.get()) {
330 scoped_ptr<FullWallet> full_wallet(
331 FullWallet::CreateFullWallet(*response_dict));
332 if (full_wallet.get())
333 observer_->OnGetFullWallet(full_wallet.release());
334 else
335 observer_->OnNetworkError(response_code);
336 } else {
337 MaybeRetry(&old_request, source, should_retry_request);
338 }
339 break;
340 }
341 case GET_WALLET_ITEMS: {
342 if (response_dict.get()) {
343 scoped_ptr<WalletItems> wallet_items(
344 WalletItems::CreateWalletItems(*response_dict));
345 if (wallet_items.get())
346 observer_->OnGetWalletItems(wallet_items.release());
347 else
348 observer_->OnNetworkError(response_code);
349 } else {
350 MaybeRetry(&old_request, source, should_retry_request);
351 }
352 break;
353 }
354 default: {
355 NOTREACHED();
356 }
357 }
358 }
359
360 WalletClient::WalletClient(
361 net::URLRequestContextGetter* context_getter) {
362 DCHECK(context_getter);
363 core_ = new Core(context_getter);
364 }
365
366 WalletClient::~WalletClient() {}
367
368 void WalletClient::GetWalletItems(
369 WalletClient::WalletClientObserver* observer) {
370 core_->GetWalletItems(observer);
371 }
372
373 void WalletClient::AcceptLegalDocuments(
374 const std::vector<std::string>& document_ids,
375 const std::string& google_transaction_id,
376 WalletClient::WalletClientObserver* observer) {
377 core_->AcceptLegalDocuments(document_ids,
378 google_transaction_id,
379 observer);
380 }
381
382 void WalletClient::EncryptOtp(
383 const void* otp,
384 size_t length,
385 WalletClient::WalletClientObserver* observer) {
386 core_->EncryptOtp(otp, length, observer);
387 }
388
389 void WalletClient::GetFullWallet(
390 const std::string& instrument_id,
391 const std::string& address_id,
392 const std::string& merchant_domain,
393 const Cart& cart,
394 const std::string& google_transaction_id,
395 const std::string& encrypted_otp,
396 const std::string& session_material,
397 WalletClient::WalletClientObserver* observer) {
398 core_->GetFullWallet(instrument_id,
399 address_id,
400 merchant_domain,
401 cart,
402 google_transaction_id,
403 encrypted_otp,
404 session_material,
405 observer);
406 }
407
408 void WalletClient::SendExtendedAutofillStatus(
409 bool success,
410 const std::string& merchant_domain,
411 const std::string& reason,
412 const std::string& google_transaction_id,
413 WalletClient::WalletClientObserver* observer) {
414 core_->SendExtendedAutofillStatus(success,
415 merchant_domain,
416 reason,
417 google_transaction_id,
418 observer);
419 }
420
421 } // end wallet namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698