| OLD | NEW |
| 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/V8PaymentDetails.h" | 12 #include "bindings/modules/v8/V8PaymentDetails.h" |
| 12 #include "core/EventTypeNames.h" | 13 #include "core/EventTypeNames.h" |
| 13 #include "core/dom/DOMException.h" | 14 #include "core/dom/DOMException.h" |
| 14 #include "core/dom/ExceptionCode.h" | 15 #include "core/dom/ExceptionCode.h" |
| 15 #include "core/events/Event.h" | 16 #include "core/events/Event.h" |
| 16 #include "core/events/EventQueue.h" | 17 #include "core/events/EventQueue.h" |
| 17 #include "core/frame/FrameOwner.h" | 18 #include "core/frame/FrameOwner.h" |
| 18 #include "core/html/HTMLIFrameElement.h" | 19 #include "core/html/HTMLIFrameElement.h" |
| 19 #include "modules/EventTargetModulesNames.h" | 20 #include "modules/EventTargetModulesNames.h" |
| 21 #include "modules/payments/AndroidPayMethodData.h" |
| 22 #include "modules/payments/AndroidPayTokenization.h" |
| 20 #include "modules/payments/HTMLIFrameElementPayments.h" | 23 #include "modules/payments/HTMLIFrameElementPayments.h" |
| 21 #include "modules/payments/PaymentAddress.h" | 24 #include "modules/payments/PaymentAddress.h" |
| 22 #include "modules/payments/PaymentItem.h" | 25 #include "modules/payments/PaymentItem.h" |
| 23 #include "modules/payments/PaymentRequestUpdateEvent.h" | 26 #include "modules/payments/PaymentRequestUpdateEvent.h" |
| 24 #include "modules/payments/PaymentResponse.h" | 27 #include "modules/payments/PaymentResponse.h" |
| 25 #include "modules/payments/PaymentShippingOption.h" | 28 #include "modules/payments/PaymentShippingOption.h" |
| 26 #include "modules/payments/PaymentsValidators.h" | 29 #include "modules/payments/PaymentsValidators.h" |
| 27 #include "mojo/public/cpp/bindings/interface_request.h" | 30 #include "mojo/public/cpp/bindings/interface_request.h" |
| 28 #include "mojo/public/cpp/bindings/wtf_array.h" | 31 #include "mojo/public/cpp/bindings/wtf_array.h" |
| 29 #include "platform/mojo/MojoHelper.h" | 32 #include "platform/mojo/MojoHelper.h" |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 output->shipping_type = PaymentShippingType::DELIVERY; | 162 output->shipping_type = PaymentShippingType::DELIVERY; |
| 160 else if (input.shippingType() == "pickup") | 163 else if (input.shippingType() == "pickup") |
| 161 output->shipping_type = PaymentShippingType::PICKUP; | 164 output->shipping_type = PaymentShippingType::PICKUP; |
| 162 else | 165 else |
| 163 output->shipping_type = PaymentShippingType::SHIPPING; | 166 output->shipping_type = PaymentShippingType::SHIPPING; |
| 164 | 167 |
| 165 return output; | 168 return output; |
| 166 } | 169 } |
| 167 }; | 170 }; |
| 168 | 171 |
| 169 template <> | |
| 170 struct TypeConverter<WTFArray<PaymentMethodDataPtr>, | |
| 171 WTF::Vector<blink::PaymentRequest::MethodData>> { | |
| 172 static WTFArray<PaymentMethodDataPtr> Convert( | |
| 173 const WTF::Vector<blink::PaymentRequest::MethodData>& input) { | |
| 174 WTFArray<PaymentMethodDataPtr> output(input.size()); | |
| 175 for (size_t i = 0; i < input.size(); ++i) { | |
| 176 output[i] = PaymentMethodData::New(); | |
| 177 output[i]->supported_methods = | |
| 178 WTF::Vector<WTF::String>(input[i].supportedMethods); | |
| 179 output[i]->stringified_data = input[i].stringifiedData; | |
| 180 } | |
| 181 return output; | |
| 182 } | |
| 183 }; | |
| 184 | |
| 185 } // namespace mojo | 172 } // namespace mojo |
| 186 | 173 |
| 187 namespace blink { | 174 namespace blink { |
| 188 namespace { | 175 namespace { |
| 189 | 176 |
| 177 using payments::mojom::blink::AndroidPayCardNetwork; |
| 178 using payments::mojom::blink::AndroidPayTokenization; |
| 179 |
| 190 // If the website does not call complete() 60 seconds after show() has been | 180 // If the website does not call complete() 60 seconds after show() has been |
| 191 // resolved, then behave as if the website called complete("fail"). | 181 // resolved, then behave as if the website called complete("fail"). |
| 192 static const int completeTimeoutSeconds = 60; | 182 static const int completeTimeoutSeconds = 60; |
| 193 | 183 |
| 184 const struct { |
| 185 const AndroidPayCardNetwork code; |
| 186 const char* name; |
| 187 } kAndroidPayNetwork[] = {{AndroidPayCardNetwork::AMEX, "AMEX"}, |
| 188 {AndroidPayCardNetwork::DISCOVER, "DISCOVER"}, |
| 189 {AndroidPayCardNetwork::MASTERCARD, "MASTERCARD"}, |
| 190 {AndroidPayCardNetwork::VISA, "VISA"}}; |
| 191 |
| 192 const struct { |
| 193 const AndroidPayTokenization code; |
| 194 const char* name; |
| 195 } kAndroidPayTokenization[] = { |
| 196 {AndroidPayTokenization::GATEWAY_TOKEN, "GATEWAY_TOKEN"}, |
| 197 {AndroidPayTokenization::NETWORK_TOKEN, "NETWORK_TOKEN"}}; |
| 198 |
| 194 // Validates ShippingOption or PaymentItem, which happen to have identical | 199 // Validates ShippingOption or PaymentItem, which happen to have identical |
| 195 // fields, except for "id", which is present only in ShippingOption. | 200 // fields, except for "id", which is present only in ShippingOption. |
| 196 template <typename T> | 201 template <typename T> |
| 197 void validateShippingOptionOrPaymentItem(const T& item, | 202 void validateShippingOptionOrPaymentItem(const T& item, |
| 198 ExceptionState& exceptionState) { | 203 ExceptionState& exceptionState) { |
| 199 if (!item.hasLabel() || item.label().isEmpty()) { | 204 if (!item.hasLabel() || item.label().isEmpty()) { |
| 200 exceptionState.throwTypeError("Item label required"); | 205 exceptionState.throwTypeError("Item label required"); |
| 201 return; | 206 return; |
| 202 } | 207 } |
| 203 | 208 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 | 347 |
| 343 String errorMessage; | 348 String errorMessage; |
| 344 if (!PaymentsValidators::isValidErrorMsgFormat(details.error(), | 349 if (!PaymentsValidators::isValidErrorMsgFormat(details.error(), |
| 345 &errorMessage)) { | 350 &errorMessage)) { |
| 346 exceptionState.throwTypeError(errorMessage); | 351 exceptionState.throwTypeError(errorMessage); |
| 347 } | 352 } |
| 348 | 353 |
| 349 return keepShippingOptions; | 354 return keepShippingOptions; |
| 350 } | 355 } |
| 351 | 356 |
| 357 void maybeSetAndroidPayMethodata( |
| 358 const ScriptValue& input, |
| 359 payments::mojom::blink::PaymentMethodDataPtr& output) { |
| 360 AndroidPayMethodData androidPay; |
| 361 TrackExceptionState exceptionState; |
| 362 V8AndroidPayMethodData::toImpl(input.isolate(), input.v8Value(), androidPay, |
| 363 exceptionState); |
| 364 if (exceptionState.hadException()) |
| 365 return; |
| 366 |
| 367 if (androidPay.hasEnvironment() && androidPay.environment() == "TEST") |
| 368 output->environment = payments::mojom::blink::AndroidPayEnvironment::TEST; |
| 369 |
| 370 output->merchant_name = androidPay.merchantName(); |
| 371 output->merchant_id = androidPay.merchantId(); |
| 372 |
| 373 if (androidPay.hasAllowedCardNetworks()) { |
| 374 output->allowed_card_networks.resize( |
| 375 androidPay.allowedCardNetworks().size()); |
| 376 size_t numberOfNetworks = 0; |
| 377 for (size_t i = 0; i < androidPay.allowedCardNetworks().size(); ++i) { |
| 378 for (size_t j = 0; j < arraysize(kAndroidPayNetwork); ++j) { |
| 379 if (androidPay.allowedCardNetworks()[i] == kAndroidPayNetwork[j].name) { |
| 380 output->allowed_card_networks[numberOfNetworks++] = |
| 381 kAndroidPayNetwork[j].code; |
| 382 break; |
| 383 } |
| 384 } |
| 385 } |
| 386 output->allowed_card_networks.resize(numberOfNetworks); |
| 387 } |
| 388 |
| 389 if (androidPay.hasPaymentMethodTokenizationParameters()) { |
| 390 const blink::AndroidPayTokenization& tokenization = |
| 391 androidPay.paymentMethodTokenizationParameters(); |
| 392 output->tokenization_type = |
| 393 payments::mojom::blink::AndroidPayTokenization::UNSPECIFIED; |
| 394 if (tokenization.hasTokenizationType()) { |
| 395 for (size_t j = 0; j < arraysize(kAndroidPayTokenization); ++j) { |
| 396 if (tokenization.tokenizationType() == |
| 397 kAndroidPayTokenization[j].name) { |
| 398 output->tokenization_type = kAndroidPayTokenization[j].code; |
| 399 break; |
| 400 } |
| 401 } |
| 402 } |
| 403 |
| 404 if (tokenization.hasParameters()) { |
| 405 Vector<String> keys; |
| 406 tokenization.parameters().getPropertyNames(keys); |
| 407 output->parameters.resize(keys.size()); |
| 408 size_t numberOfParameters = 0; |
| 409 String value; |
| 410 for (size_t i = 0; i < keys.size(); ++i) { |
| 411 if (!DictionaryHelper::get(tokenization.parameters(), keys[i], value)) |
| 412 continue; |
| 413 output->parameters[numberOfParameters] = |
| 414 payments::mojom::blink::AndroidPayTokenizationParameter::New(); |
| 415 output->parameters[numberOfParameters]->key = keys[i]; |
| 416 output->parameters[numberOfParameters]->value = value; |
| 417 ++numberOfParameters; |
| 418 } |
| 419 output->parameters.resize(numberOfParameters); |
| 420 } |
| 421 } |
| 422 } |
| 423 |
| 352 void validateAndConvertPaymentMethodData( | 424 void validateAndConvertPaymentMethodData( |
| 353 const HeapVector<PaymentMethodData>& paymentMethodDataVector, | 425 const HeapVector<PaymentMethodData>& input, |
| 354 Vector<PaymentRequest::MethodData>* methodData, | 426 Vector<payments::mojom::blink::PaymentMethodDataPtr>& output, |
| 355 ExceptionState& exceptionState) { | 427 ExceptionState& exceptionState) { |
| 356 if (paymentMethodDataVector.isEmpty()) { | 428 if (input.isEmpty()) { |
| 357 exceptionState.throwTypeError( | 429 exceptionState.throwTypeError( |
| 358 "Must specify at least one payment method identifier"); | 430 "Must specify at least one payment method identifier"); |
| 359 return; | 431 return; |
| 360 } | 432 } |
| 361 | 433 |
| 362 for (const auto& paymentMethodData : paymentMethodDataVector) { | 434 output.resize(input.size()); |
| 435 for (size_t i = 0; i < input.size(); ++i) { |
| 436 const auto& paymentMethodData = input[i]; |
| 363 if (paymentMethodData.supportedMethods().isEmpty()) { | 437 if (paymentMethodData.supportedMethods().isEmpty()) { |
| 364 exceptionState.throwTypeError( | 438 exceptionState.throwTypeError( |
| 365 "Must specify at least one payment method identifier"); | 439 "Must specify at least one payment method identifier"); |
| 366 return; | 440 return; |
| 367 } | 441 } |
| 368 | 442 |
| 369 String stringifiedData = ""; | 443 String stringifiedData = ""; |
| 370 if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) { | 444 if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) { |
| 371 if (!paymentMethodData.data().v8Value()->IsObject() || | 445 if (!paymentMethodData.data().v8Value()->IsObject() || |
| 372 paymentMethodData.data().v8Value()->IsArray()) { | 446 paymentMethodData.data().v8Value()->IsArray()) { |
| 373 exceptionState.throwTypeError( | 447 exceptionState.throwTypeError( |
| 374 "Data should be a JSON-serializable object"); | 448 "Data should be a JSON-serializable object"); |
| 375 return; | 449 return; |
| 376 } | 450 } |
| 377 | 451 |
| 378 v8::Local<v8::String> value; | 452 v8::Local<v8::String> value; |
| 379 if (!v8::JSON::Stringify( | 453 if (!v8::JSON::Stringify( |
| 380 paymentMethodData.data().context(), | 454 paymentMethodData.data().context(), |
| 381 paymentMethodData.data().v8Value().As<v8::Object>()) | 455 paymentMethodData.data().v8Value().As<v8::Object>()) |
| 382 .ToLocal(&value)) { | 456 .ToLocal(&value)) { |
| 383 exceptionState.throwTypeError( | 457 exceptionState.throwTypeError( |
| 384 "Unable to parse payment method specific data"); | 458 "Unable to parse payment method specific data"); |
| 385 return; | 459 return; |
| 386 } | 460 } |
| 387 stringifiedData = | 461 stringifiedData = |
| 388 v8StringToWebCoreString<String>(value, DoNotExternalize); | 462 v8StringToWebCoreString<String>(value, DoNotExternalize); |
| 389 } | 463 } |
| 390 methodData->append(PaymentRequest::MethodData( | 464 |
| 391 paymentMethodData.supportedMethods(), stringifiedData)); | 465 output[i] = payments::mojom::blink::PaymentMethodData::New(); |
| 466 output[i]->supported_methods = paymentMethodData.supportedMethods(); |
| 467 output[i]->stringified_data = stringifiedData; |
| 468 maybeSetAndroidPayMethodata(paymentMethodData.data(), output[i]); |
| 392 } | 469 } |
| 393 } | 470 } |
| 394 | 471 |
| 395 String getSelectedShippingOption(const PaymentDetails& details) { | 472 String getSelectedShippingOption(const PaymentDetails& details) { |
| 396 String result; | 473 String result; |
| 397 if (!details.hasShippingOptions()) | 474 if (!details.hasShippingOptions()) |
| 398 return result; | 475 return result; |
| 399 | 476 |
| 400 for (int i = details.shippingOptions().size() - 1; i >= 0; --i) { | 477 for (int i = details.shippingOptions().size() - 1; i >= 0; --i) { |
| 401 if (details.shippingOptions()[i].hasSelected() && | 478 if (details.shippingOptions()[i].hasSelected() && |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 if (ownerElement && isHTMLIFrameElement(ownerElement)) { | 525 if (ownerElement && isHTMLIFrameElement(ownerElement)) { |
| 449 HTMLIFrameElement* iframe = toHTMLIFrameElement(ownerElement); | 526 HTMLIFrameElement* iframe = toHTMLIFrameElement(ownerElement); |
| 450 if (HTMLIFrameElementPayments::from(*iframe).allowPaymentRequest(*iframe)) | 527 if (HTMLIFrameElementPayments::from(*iframe).allowPaymentRequest(*iframe)) |
| 451 return allowedToUsePaymentRequest(frame->tree().parent()); | 528 return allowedToUsePaymentRequest(frame->tree().parent()); |
| 452 } | 529 } |
| 453 | 530 |
| 454 // 4. Return false. | 531 // 4. Return false. |
| 455 return false; | 532 return false; |
| 456 } | 533 } |
| 457 | 534 |
| 458 WTF::Vector<payments::mojom::blink::PaymentMethodDataPtr> | |
| 459 ConvertPaymentMethodData( | |
| 460 const Vector<PaymentRequest::MethodData>& blinkMethods) { | |
| 461 WTF::Vector<payments::mojom::blink::PaymentMethodDataPtr> mojoMethods( | |
| 462 blinkMethods.size()); | |
| 463 for (size_t i = 0; i < blinkMethods.size(); ++i) { | |
| 464 mojoMethods[i] = payments::mojom::blink::PaymentMethodData::New(); | |
| 465 mojoMethods[i]->supported_methods = | |
| 466 WTF::Vector<WTF::String>(blinkMethods[i].supportedMethods); | |
| 467 mojoMethods[i]->stringified_data = blinkMethods[i].stringifiedData; | |
| 468 } | |
| 469 return mojoMethods; | |
| 470 } | |
| 471 | |
| 472 } // namespace | 535 } // namespace |
| 473 | 536 |
| 474 PaymentRequest* PaymentRequest::create( | 537 PaymentRequest* PaymentRequest::create( |
| 475 ScriptState* scriptState, | 538 ScriptState* scriptState, |
| 476 const HeapVector<PaymentMethodData>& methodData, | 539 const HeapVector<PaymentMethodData>& methodData, |
| 477 const PaymentDetails& details, | 540 const PaymentDetails& details, |
| 478 ExceptionState& exceptionState) { | 541 ExceptionState& exceptionState) { |
| 479 return new PaymentRequest(scriptState, methodData, details, PaymentOptions(), | 542 return new PaymentRequest(scriptState, methodData, details, PaymentOptions(), |
| 480 exceptionState); | 543 exceptionState); |
| 481 } | 544 } |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 632 PaymentRequest::PaymentRequest(ScriptState* scriptState, | 695 PaymentRequest::PaymentRequest(ScriptState* scriptState, |
| 633 const HeapVector<PaymentMethodData>& methodData, | 696 const HeapVector<PaymentMethodData>& methodData, |
| 634 const PaymentDetails& details, | 697 const PaymentDetails& details, |
| 635 const PaymentOptions& options, | 698 const PaymentOptions& options, |
| 636 ExceptionState& exceptionState) | 699 ExceptionState& exceptionState) |
| 637 : ContextLifecycleObserver(scriptState->getExecutionContext()), | 700 : ContextLifecycleObserver(scriptState->getExecutionContext()), |
| 638 ActiveScriptWrappable(this), | 701 ActiveScriptWrappable(this), |
| 639 m_options(options), | 702 m_options(options), |
| 640 m_clientBinding(this), | 703 m_clientBinding(this), |
| 641 m_completeTimer(this, &PaymentRequest::onCompleteTimeout) { | 704 m_completeTimer(this, &PaymentRequest::onCompleteTimeout) { |
| 642 Vector<MethodData> validatedMethodData; | 705 Vector<payments::mojom::blink::PaymentMethodDataPtr> validatedMethodData; |
| 643 validateAndConvertPaymentMethodData(methodData, &validatedMethodData, | 706 validateAndConvertPaymentMethodData(methodData, validatedMethodData, |
| 644 exceptionState); | 707 exceptionState); |
| 645 if (exceptionState.hadException()) | 708 if (exceptionState.hadException()) |
| 646 return; | 709 return; |
| 647 | 710 |
| 648 if (!scriptState->getExecutionContext()->isSecureContext()) { | 711 if (!scriptState->getExecutionContext()->isSecureContext()) { |
| 649 exceptionState.throwSecurityError("Must be in a secure context"); | 712 exceptionState.throwSecurityError("Must be in a secure context"); |
| 650 return; | 713 return; |
| 651 } | 714 } |
| 652 | 715 |
| 653 if (!allowedToUsePaymentRequest(scriptState->domWindow()->frame())) { | 716 if (!allowedToUsePaymentRequest(scriptState->domWindow()->frame())) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 672 m_shippingType = getValidShippingType(m_options.shippingType()); | 735 m_shippingType = getValidShippingType(m_options.shippingType()); |
| 673 } | 736 } |
| 674 | 737 |
| 675 scriptState->domWindow()->frame()->interfaceProvider()->getInterface( | 738 scriptState->domWindow()->frame()->interfaceProvider()->getInterface( |
| 676 mojo::GetProxy(&m_paymentProvider)); | 739 mojo::GetProxy(&m_paymentProvider)); |
| 677 m_paymentProvider.set_connection_error_handler(convertToBaseCallback( | 740 m_paymentProvider.set_connection_error_handler(convertToBaseCallback( |
| 678 WTF::bind(&PaymentRequest::OnError, wrapWeakPersistent(this), | 741 WTF::bind(&PaymentRequest::OnError, wrapWeakPersistent(this), |
| 679 payments::mojom::blink::PaymentErrorReason::UNKNOWN))); | 742 payments::mojom::blink::PaymentErrorReason::UNKNOWN))); |
| 680 m_paymentProvider->Init( | 743 m_paymentProvider->Init( |
| 681 m_clientBinding.CreateInterfacePtrAndBind(), | 744 m_clientBinding.CreateInterfacePtrAndBind(), |
| 682 ConvertPaymentMethodData(validatedMethodData), | 745 std::move(validatedMethodData), |
| 683 maybeKeepShippingOptions( | 746 maybeKeepShippingOptions( |
| 684 payments::mojom::blink::PaymentDetails::From(details), | 747 payments::mojom::blink::PaymentDetails::From(details), |
| 685 keepShippingOptions && m_options.requestShipping()), | 748 keepShippingOptions && m_options.requestShipping()), |
| 686 payments::mojom::blink::PaymentOptions::From(m_options)); | 749 payments::mojom::blink::PaymentOptions::From(m_options)); |
| 687 } | 750 } |
| 688 | 751 |
| 689 void PaymentRequest::contextDestroyed() { | 752 void PaymentRequest::contextDestroyed() { |
| 690 clearResolversAndCloseMojoConnection(); | 753 clearResolversAndCloseMojoConnection(); |
| 691 } | 754 } |
| 692 | 755 |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 858 m_completeTimer.stop(); | 921 m_completeTimer.stop(); |
| 859 m_completeResolver.clear(); | 922 m_completeResolver.clear(); |
| 860 m_showResolver.clear(); | 923 m_showResolver.clear(); |
| 861 m_abortResolver.clear(); | 924 m_abortResolver.clear(); |
| 862 if (m_clientBinding.is_bound()) | 925 if (m_clientBinding.is_bound()) |
| 863 m_clientBinding.Close(); | 926 m_clientBinding.Close(); |
| 864 m_paymentProvider.reset(); | 927 m_paymentProvider.reset(); |
| 865 } | 928 } |
| 866 | 929 |
| 867 } // namespace blink | 930 } // namespace blink |
| OLD | NEW |