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

Side by Side Diff: third_party/WebKit/Source/modules/payments/PaymentRequest.cpp

Issue 2501593003: Implement the new basic card specification. (Closed)
Patch Set: Rebase Created 3 years, 11 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "modules/payments/PaymentRequest.h" 5 #include "modules/payments/PaymentRequest.h"
6 6
7 #include "bindings/core/v8/ExceptionState.h" 7 #include "bindings/core/v8/ExceptionState.h"
8 #include "bindings/core/v8/ScriptPromiseResolver.h" 8 #include "bindings/core/v8/ScriptPromiseResolver.h"
9 #include "bindings/core/v8/ScriptState.h" 9 #include "bindings/core/v8/ScriptState.h"
10 #include "bindings/core/v8/V8StringResource.h" 10 #include "bindings/core/v8/V8StringResource.h"
11 #include "bindings/modules/v8/V8AndroidPayMethodData.h" 11 #include "bindings/modules/v8/V8AndroidPayMethodData.h"
12 #include "bindings/modules/v8/V8BasicCardRequest.h"
12 #include "bindings/modules/v8/V8PaymentDetails.h" 13 #include "bindings/modules/v8/V8PaymentDetails.h"
13 #include "core/EventTypeNames.h" 14 #include "core/EventTypeNames.h"
14 #include "core/dom/DOMException.h" 15 #include "core/dom/DOMException.h"
15 #include "core/dom/ExceptionCode.h" 16 #include "core/dom/ExceptionCode.h"
16 #include "core/events/Event.h" 17 #include "core/events/Event.h"
17 #include "core/events/EventQueue.h" 18 #include "core/events/EventQueue.h"
18 #include "core/frame/FrameOwner.h" 19 #include "core/frame/FrameOwner.h"
19 #include "core/html/HTMLIFrameElement.h" 20 #include "core/html/HTMLIFrameElement.h"
20 #include "modules/EventTargetModulesNames.h" 21 #include "modules/EventTargetModulesNames.h"
21 #include "modules/payments/AndroidPayMethodData.h" 22 #include "modules/payments/AndroidPayMethodData.h"
22 #include "modules/payments/AndroidPayTokenization.h" 23 #include "modules/payments/AndroidPayTokenization.h"
24 #include "modules/payments/BasicCardRequest.h"
23 #include "modules/payments/HTMLIFrameElementPayments.h" 25 #include "modules/payments/HTMLIFrameElementPayments.h"
24 #include "modules/payments/PaymentAddress.h" 26 #include "modules/payments/PaymentAddress.h"
25 #include "modules/payments/PaymentItem.h" 27 #include "modules/payments/PaymentItem.h"
26 #include "modules/payments/PaymentRequestUpdateEvent.h" 28 #include "modules/payments/PaymentRequestUpdateEvent.h"
27 #include "modules/payments/PaymentResponse.h" 29 #include "modules/payments/PaymentResponse.h"
28 #include "modules/payments/PaymentShippingOption.h" 30 #include "modules/payments/PaymentShippingOption.h"
29 #include "modules/payments/PaymentsValidators.h" 31 #include "modules/payments/PaymentsValidators.h"
30 #include "mojo/public/cpp/bindings/interface_request.h" 32 #include "mojo/public/cpp/bindings/interface_request.h"
31 #include "mojo/public/cpp/bindings/wtf_array.h" 33 #include "mojo/public/cpp/bindings/wtf_array.h"
32 #include "platform/RuntimeEnabledFeatures.h" 34 #include "platform/RuntimeEnabledFeatures.h"
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 112
111 return output; 113 return output;
112 } 114 }
113 }; 115 };
114 116
115 } // namespace mojo 117 } // namespace mojo
116 118
117 namespace blink { 119 namespace blink {
118 namespace { 120 namespace {
119 121
120 using payments::mojom::blink::AndroidPayCardNetwork;
121 using payments::mojom::blink::AndroidPayTokenization;
122
123 // If the website does not call complete() 60 seconds after show() has been 122 // If the website does not call complete() 60 seconds after show() has been
124 // resolved, then behave as if the website called complete("fail"). 123 // resolved, then behave as if the website called complete("fail").
125 static const int completeTimeoutSeconds = 60; 124 static const int completeTimeoutSeconds = 60;
126 125
127 const struct {
128 const AndroidPayCardNetwork code;
129 const char* name;
130 } kAndroidPayNetwork[] = {{AndroidPayCardNetwork::AMEX, "AMEX"},
131 {AndroidPayCardNetwork::DISCOVER, "DISCOVER"},
132 {AndroidPayCardNetwork::MASTERCARD, "MASTERCARD"},
133 {AndroidPayCardNetwork::VISA, "VISA"}};
134
135 const struct {
136 const AndroidPayTokenization code;
137 const char* name;
138 } kAndroidPayTokenization[] = {
139 {AndroidPayTokenization::GATEWAY_TOKEN, "GATEWAY_TOKEN"},
140 {AndroidPayTokenization::NETWORK_TOKEN, "NETWORK_TOKEN"}};
141
142 // Validates ShippingOption or PaymentItem, which happen to have identical 126 // Validates ShippingOption or PaymentItem, which happen to have identical
143 // fields, except for "id", which is present only in ShippingOption. 127 // fields, except for "id", which is present only in ShippingOption.
144 template <typename T> 128 template <typename T>
145 void validateShippingOptionOrPaymentItem(const T& item, 129 void validateShippingOptionOrPaymentItem(const T& item,
146 ExceptionState& exceptionState) { 130 ExceptionState& exceptionState) {
147 if (!item.hasLabel() || item.label().isEmpty()) { 131 if (!item.hasLabel() || item.label().isEmpty()) {
148 exceptionState.throwTypeError("Item label required"); 132 exceptionState.throwTypeError("Item label required");
149 return; 133 return;
150 } 134 }
151 135
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 return; 214 return;
231 215
232 if (input.amount().value()[0] == '-') { 216 if (input.amount().value()[0] == '-') {
233 exceptionState.throwTypeError("Total amount value should be non-negative"); 217 exceptionState.throwTypeError("Total amount value should be non-negative");
234 return; 218 return;
235 } 219 }
236 220
237 output = payments::mojom::blink::PaymentItem::From(input); 221 output = payments::mojom::blink::PaymentItem::From(input);
238 } 222 }
239 223
240 void maybeSetAndroidPayMethodData(const ScriptValue& input, 224 // Parses Android Pay data to avoid parsing JSON in the browser.
241 PaymentMethodDataPtr& output, 225 void setAndroidPayMethodData(const ScriptValue& input,
242 ExceptionState& exceptionState) { 226 PaymentMethodDataPtr& output,
227 ExceptionState& exceptionState) {
243 AndroidPayMethodData androidPay; 228 AndroidPayMethodData androidPay;
244 DummyExceptionStateForTesting dummyExceptionState;
245 V8AndroidPayMethodData::toImpl(input.isolate(), input.v8Value(), androidPay, 229 V8AndroidPayMethodData::toImpl(input.isolate(), input.v8Value(), androidPay,
246 dummyExceptionState); 230 exceptionState);
247 if (dummyExceptionState.hadException()) 231 if (exceptionState.hadException())
248 return; 232 return;
249 233
250 if (androidPay.hasEnvironment() && androidPay.environment() == "TEST") 234 if (androidPay.hasEnvironment() && androidPay.environment() == "TEST")
251 output->environment = payments::mojom::blink::AndroidPayEnvironment::TEST; 235 output->environment = payments::mojom::blink::AndroidPayEnvironment::TEST;
252 236
253 output->merchant_name = androidPay.merchantName(); 237 output->merchant_name = androidPay.merchantName();
254 output->merchant_id = androidPay.merchantId(); 238 output->merchant_id = androidPay.merchantId();
255 239
256 // 0 means the merchant did not specify or it was an invalid value 240 // 0 means the merchant did not specify or it was an invalid value
257 output->min_google_play_services_version = 0; 241 output->min_google_play_services_version = 0;
258 if (androidPay.hasMinGooglePlayServicesVersion()) { 242 if (androidPay.hasMinGooglePlayServicesVersion()) {
259 bool ok = false; 243 bool ok = false;
260 int minGooglePlayServicesVersion = 244 int minGooglePlayServicesVersion =
261 androidPay.minGooglePlayServicesVersion().toIntStrict(&ok); 245 androidPay.minGooglePlayServicesVersion().toIntStrict(&ok);
262 if (ok) { 246 if (ok) {
263 output->min_google_play_services_version = minGooglePlayServicesVersion; 247 output->min_google_play_services_version = minGooglePlayServicesVersion;
264 } 248 }
265 } 249 }
266 250
267 if (androidPay.hasAllowedCardNetworks()) { 251 if (androidPay.hasAllowedCardNetworks()) {
252 using payments::mojom::blink::AndroidPayCardNetwork;
253
254 const struct {
255 const AndroidPayCardNetwork code;
256 const char* const name;
257 } androidPayNetwork[] = {{AndroidPayCardNetwork::AMEX, "AMEX"},
258 {AndroidPayCardNetwork::DISCOVER, "DISCOVER"},
259 {AndroidPayCardNetwork::MASTERCARD, "MASTERCARD"},
260 {AndroidPayCardNetwork::VISA, "VISA"}};
261
268 for (const String& allowedCardNetwork : androidPay.allowedCardNetworks()) { 262 for (const String& allowedCardNetwork : androidPay.allowedCardNetworks()) {
269 for (size_t i = 0; i < arraysize(kAndroidPayNetwork); ++i) { 263 for (size_t i = 0; i < arraysize(androidPayNetwork); ++i) {
270 if (allowedCardNetwork == kAndroidPayNetwork[i].name) { 264 if (allowedCardNetwork == androidPayNetwork[i].name) {
271 output->allowed_card_networks.append(kAndroidPayNetwork[i].code); 265 output->allowed_card_networks.append(androidPayNetwork[i].code);
272 break; 266 break;
273 } 267 }
274 } 268 }
275 } 269 }
276 } 270 }
277 271
278 if (androidPay.hasPaymentMethodTokenizationParameters()) { 272 if (androidPay.hasPaymentMethodTokenizationParameters()) {
279 const blink::AndroidPayTokenization& tokenization = 273 const blink::AndroidPayTokenization& tokenization =
280 androidPay.paymentMethodTokenizationParameters(); 274 androidPay.paymentMethodTokenizationParameters();
281 output->tokenization_type = 275 output->tokenization_type =
282 payments::mojom::blink::AndroidPayTokenization::UNSPECIFIED; 276 payments::mojom::blink::AndroidPayTokenization::UNSPECIFIED;
283 if (tokenization.hasTokenizationType()) { 277 if (tokenization.hasTokenizationType()) {
284 for (size_t i = 0; i < arraysize(kAndroidPayTokenization); ++i) { 278 using payments::mojom::blink::AndroidPayTokenization;
285 if (tokenization.tokenizationType() == 279
286 kAndroidPayTokenization[i].name) { 280 const struct {
287 output->tokenization_type = kAndroidPayTokenization[i].code; 281 const AndroidPayTokenization code;
282 const char* const name;
283 } androidPayTokenization[] = {
284 {AndroidPayTokenization::GATEWAY_TOKEN, "GATEWAY_TOKEN"},
285 {AndroidPayTokenization::NETWORK_TOKEN, "NETWORK_TOKEN"}};
286
287 for (size_t i = 0; i < arraysize(androidPayTokenization); ++i) {
288 if (tokenization.tokenizationType() == androidPayTokenization[i].name) {
289 output->tokenization_type = androidPayTokenization[i].code;
288 break; 290 break;
289 } 291 }
290 } 292 }
291 } 293 }
292 294
293 if (tokenization.hasParameters()) { 295 if (tokenization.hasParameters()) {
294 const Vector<String>& keys = 296 const Vector<String>& keys =
295 tokenization.parameters().getPropertyNames(exceptionState); 297 tokenization.parameters().getPropertyNames(exceptionState);
296 if (exceptionState.hadException()) 298 if (exceptionState.hadException())
297 return; 299 return;
298 String value; 300 String value;
299 for (const String& key : keys) { 301 for (const String& key : keys) {
300 if (!DictionaryHelper::get(tokenization.parameters(), key, value)) 302 if (!DictionaryHelper::get(tokenization.parameters(), key, value))
301 continue; 303 continue;
302 output->parameters.append( 304 output->parameters.append(
303 payments::mojom::blink::AndroidPayTokenizationParameter::New()); 305 payments::mojom::blink::AndroidPayTokenizationParameter::New());
304 output->parameters.back()->key = key; 306 output->parameters.back()->key = key;
305 output->parameters.back()->value = value; 307 output->parameters.back()->value = value;
306 } 308 }
307 } 309 }
308 } 310 }
309 } 311 }
310 312
311 void stringifyAndParseMethodSpecificData(const ScriptValue& input, 313 // Parses basic-card data to avoid parsing JSON in the browser.
314 void setBasicCardMethodData(const ScriptValue& input,
315 PaymentMethodDataPtr& output,
316 ExceptionState& exceptionState) {
317 BasicCardRequest basicCard;
318 V8BasicCardRequest::toImpl(input.isolate(), input.v8Value(), basicCard,
319 exceptionState);
320 if (exceptionState.hadException())
321 return;
322
323 if (basicCard.hasSupportedNetworks()) {
324 using payments::mojom::blink::BasicCardNetwork;
325
326 const struct {
327 const BasicCardNetwork code;
328 const char* const name;
329 } basicCardNetworks[] = {{BasicCardNetwork::AMEX, "amex"},
330 {BasicCardNetwork::DINERS, "diners"},
331 {BasicCardNetwork::DISCOVER, "discover"},
332 {BasicCardNetwork::JCB, "jcb"},
333 {BasicCardNetwork::MASTERCARD, "mastercard"},
334 {BasicCardNetwork::UNIONPAY, "unionpay"},
335 {BasicCardNetwork::VISA, "visa"}};
336
337 for (const String& network : basicCard.supportedNetworks()) {
338 for (size_t i = 0; i < arraysize(basicCardNetworks); ++i) {
339 if (network == basicCardNetworks[i].name) {
340 output->supported_networks.append(basicCardNetworks[i].code);
341 break;
342 }
343 }
344 }
345 }
346
347 if (basicCard.hasSupportedTypes()) {
348 using payments::mojom::blink::BasicCardType;
349
350 const struct {
351 const BasicCardType code;
352 const char* const name;
353 } basicCardTypes[] = {{BasicCardType::CREDIT, "credit"},
354 {BasicCardType::DEBIT, "debit"},
355 {BasicCardType::PREPAID, "prepaid"}};
356
357 for (const String& type : basicCard.supportedTypes()) {
358 for (size_t i = 0; i < arraysize(basicCardTypes); ++i) {
359 if (type == basicCardTypes[i].name) {
360 output->supported_types.append(basicCardTypes[i].code);
361 break;
362 }
363 }
364 }
365 }
366 }
367
368 void stringifyAndParseMethodSpecificData(const Vector<String>& supportedMethods,
369 const ScriptValue& input,
312 PaymentMethodDataPtr& output, 370 PaymentMethodDataPtr& output,
313 ExceptionState& exceptionState) { 371 ExceptionState& exceptionState) {
314 DCHECK(!input.isEmpty()); 372 DCHECK(!input.isEmpty());
315 if (!input.v8Value()->IsObject() || input.v8Value()->IsArray()) { 373 if (!input.v8Value()->IsObject() || input.v8Value()->IsArray()) {
316 exceptionState.throwTypeError("Data should be a JSON-serializable object"); 374 exceptionState.throwTypeError("Data should be a JSON-serializable object");
317 return; 375 return;
318 } 376 }
319 377
320 v8::Local<v8::String> value; 378 v8::Local<v8::String> value;
321 if (!v8::JSON::Stringify(input.context(), input.v8Value().As<v8::Object>()) 379 if (!v8::JSON::Stringify(input.context(), input.v8Value().As<v8::Object>())
322 .ToLocal(&value)) { 380 .ToLocal(&value)) {
323 exceptionState.throwTypeError( 381 exceptionState.throwTypeError(
324 "Unable to parse payment method specific data"); 382 "Unable to parse payment method specific data");
325 return; 383 return;
326 } 384 }
327 385
328 output->stringified_data = 386 output->stringified_data =
329 v8StringToWebCoreString<String>(value, DoNotExternalize); 387 v8StringToWebCoreString<String>(value, DoNotExternalize);
330 maybeSetAndroidPayMethodData(input, output, exceptionState); 388
389 if (supportedMethods.contains("https://android.com/pay")) {
390 setAndroidPayMethodData(input, output, exceptionState);
391 if (exceptionState.hadException())
Marijn Kruisselbrink 2017/01/05 22:38:03 I recently came across Source/bindings/core/v8/Exc
haraken 2017/01/06 00:04:17 I intentionally removed DummyExceptionStateForTest
Marijn Kruisselbrink 2017/01/06 00:16:07 I think the reason why exceptions are being ignore
392 exceptionState.clearException();
393 }
394
395 if (RuntimeEnabledFeatures::paymentRequestBasicCardEnabled() &&
396 supportedMethods.contains("basic-card")) {
397 setBasicCardMethodData(input, output, exceptionState);
398 if (exceptionState.hadException())
399 exceptionState.clearException();
400 }
331 } 401 }
332 402
333 void validateAndConvertPaymentDetailsModifiers( 403 void validateAndConvertPaymentDetailsModifiers(
334 const HeapVector<PaymentDetailsModifier>& input, 404 const HeapVector<PaymentDetailsModifier>& input,
335 Vector<PaymentDetailsModifierPtr>& output, 405 Vector<PaymentDetailsModifierPtr>& output,
336 ExceptionState& exceptionState) { 406 ExceptionState& exceptionState) {
337 if (input.isEmpty()) { 407 if (input.isEmpty()) {
338 exceptionState.throwTypeError( 408 exceptionState.throwTypeError(
339 "Must specify at least one payment details modifier"); 409 "Must specify at least one payment details modifier");
340 return; 410 return;
(...skipping 21 matching lines...) Expand all
362 "Must specify at least one payment method identifier"); 432 "Must specify at least one payment method identifier");
363 return; 433 return;
364 } 434 }
365 435
366 output.back()->method_data = 436 output.back()->method_data =
367 payments::mojom::blink::PaymentMethodData::New(); 437 payments::mojom::blink::PaymentMethodData::New();
368 output.back()->method_data->supported_methods = modifier.supportedMethods(); 438 output.back()->method_data->supported_methods = modifier.supportedMethods();
369 439
370 if (modifier.hasData() && !modifier.data().isEmpty()) { 440 if (modifier.hasData() && !modifier.data().isEmpty()) {
371 stringifyAndParseMethodSpecificData( 441 stringifyAndParseMethodSpecificData(
372 modifier.data(), output.back()->method_data, exceptionState); 442 modifier.supportedMethods(), modifier.data(),
443 output.back()->method_data, exceptionState);
373 } else { 444 } else {
374 output.back()->method_data->stringified_data = ""; 445 output.back()->method_data->stringified_data = "";
375 } 446 }
376 } 447 }
377 } 448 }
378 449
379 String getSelectedShippingOption( 450 String getSelectedShippingOption(
380 const Vector<PaymentShippingOptionPtr>& shippingOptions) { 451 const Vector<PaymentShippingOptionPtr>& shippingOptions) {
381 String result; 452 String result;
382 for (const PaymentShippingOptionPtr& shippingOption : shippingOptions) { 453 for (const PaymentShippingOptionPtr& shippingOption : shippingOptions) {
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 if (paymentMethodData.supportedMethods().isEmpty()) { 521 if (paymentMethodData.supportedMethods().isEmpty()) {
451 exceptionState.throwTypeError( 522 exceptionState.throwTypeError(
452 "Must specify at least one payment method identifier"); 523 "Must specify at least one payment method identifier");
453 return; 524 return;
454 } 525 }
455 526
456 output.append(payments::mojom::blink::PaymentMethodData::New()); 527 output.append(payments::mojom::blink::PaymentMethodData::New());
457 output.back()->supported_methods = paymentMethodData.supportedMethods(); 528 output.back()->supported_methods = paymentMethodData.supportedMethods();
458 529
459 if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) { 530 if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) {
460 stringifyAndParseMethodSpecificData(paymentMethodData.data(), 531 stringifyAndParseMethodSpecificData(paymentMethodData.supportedMethods(),
532 paymentMethodData.data(),
461 output.back(), exceptionState); 533 output.back(), exceptionState);
462 } else { 534 } else {
463 output.back()->stringified_data = ""; 535 output.back()->stringified_data = "";
464 } 536 }
465 } 537 }
466 } 538 }
467 539
468 String getValidShippingType(const String& shippingType) { 540 String getValidShippingType(const String& shippingType) {
469 static const char* const validValues[] = { 541 static const char* const validValues[] = {
470 "shipping", "delivery", "pickup", 542 "shipping", "delivery", "pickup",
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after
920 m_completeResolver.clear(); 992 m_completeResolver.clear();
921 m_showResolver.clear(); 993 m_showResolver.clear();
922 m_abortResolver.clear(); 994 m_abortResolver.clear();
923 m_canMakePaymentResolver.clear(); 995 m_canMakePaymentResolver.clear();
924 if (m_clientBinding.is_bound()) 996 if (m_clientBinding.is_bound())
925 m_clientBinding.Close(); 997 m_clientBinding.Close();
926 m_paymentProvider.reset(); 998 m_paymentProvider.reset();
927 } 999 }
928 1000
929 } // namespace blink 1001 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698