Chromium Code Reviews| 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 |
| 190 // If the website does not call complete() 60 seconds after show() has been | 177 // If the website does not call complete() 60 seconds after show() has been |
| 191 // resolved, then behave as if the website called complete("fail"). | 178 // resolved, then behave as if the website called complete("fail"). |
| 192 static const int completeTimeoutSeconds = 60; | 179 static const int completeTimeoutSeconds = 60; |
| 193 | 180 |
| 194 // Validates ShippingOption or PaymentItem, which happen to have identical | 181 // Validates ShippingOption or PaymentItem, which happen to have identical |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 342 | 329 |
| 343 String errorMessage; | 330 String errorMessage; |
| 344 if (!PaymentsValidators::isValidErrorMsgFormat(details.error(), | 331 if (!PaymentsValidators::isValidErrorMsgFormat(details.error(), |
| 345 &errorMessage)) { | 332 &errorMessage)) { |
| 346 exceptionState.throwTypeError(errorMessage); | 333 exceptionState.throwTypeError(errorMessage); |
| 347 } | 334 } |
| 348 | 335 |
| 349 return keepShippingOptions; | 336 return keepShippingOptions; |
| 350 } | 337 } |
| 351 | 338 |
| 339 void maybeSetAndroidPayMethodata( | |
| 340 const ScriptValue& input, | |
| 341 payments::mojom::blink::PaymentMethodDataPtr& output) { | |
| 342 AndroidPayMethodData androidPay; | |
| 343 TrackExceptionState exceptionState; | |
| 344 V8AndroidPayMethodData::toImpl(input.isolate(), input.v8Value(), androidPay, | |
| 345 exceptionState); | |
| 346 if (exceptionState.hadException()) | |
| 347 return; | |
| 348 | |
| 349 if (androidPay.hasEnvironment() && androidPay.environment() == "TEST") | |
| 350 output->environment = payments::mojom::blink::AndroidPayEnvironment::TEST; | |
| 351 | |
| 352 output->merchant_name = androidPay.merchantName(); | |
| 353 output->merchant_id = androidPay.merchantId(); | |
| 354 | |
| 355 if (androidPay.hasAllowedCardNetworks()) { | |
| 356 output->allowed_card_networks.resize( | |
| 357 androidPay.allowedCardNetworks().size()); | |
| 358 for (size_t i = 0; i < androidPay.allowedCardNetworks().size(); ++i) { | |
| 359 const String& network = androidPay.allowedCardNetworks()[i]; | |
| 360 if (network == "AMEX") { | |
| 361 output->allowed_card_networks[i] = | |
| 362 payments::mojom::blink::AndroidPayCardNetwork::AMEX; | |
| 363 } else if (network == "DISCOVER") { | |
| 364 output->allowed_card_networks[i] = | |
| 365 payments::mojom::blink::AndroidPayCardNetwork::DISCOVER; | |
| 366 } else if (network == "MASTERCARD") { | |
| 367 output->allowed_card_networks[i] = | |
| 368 payments::mojom::blink::AndroidPayCardNetwork::MASTERCARD; | |
| 369 } else if (network == "VISA") { | |
| 370 output->allowed_card_networks[i] = | |
| 371 payments::mojom::blink::AndroidPayCardNetwork::VISA; | |
| 372 } else { | |
| 373 output->allowed_card_networks[i] = | |
| 374 payments::mojom::blink::AndroidPayCardNetwork::UNKNOWN; | |
| 375 } | |
| 376 } | |
| 377 } | |
| 378 | |
| 379 if (androidPay.hasPaymentMethodTokenizationParameters()) { | |
| 380 const AndroidPayTokenization& tokenization = | |
| 381 androidPay.paymentMethodTokenizationParameters(); | |
| 382 if (tokenization.hasTokenizationType()) { | |
| 383 if (tokenization.tokenizationType() == "GATEWAY_TOKEN") { | |
| 384 output->tokenization_type = | |
| 385 payments::mojom::blink::AndroidPayTokenization::GATEWAY_TOKEN; | |
| 386 } else if (tokenization.tokenizationType() == "NETWORK_TOKEN") { | |
| 387 output->tokenization_type = | |
| 388 payments::mojom::blink::AndroidPayTokenization::NETWORK_TOKEN; | |
| 389 } else { | |
| 390 output->tokenization_type = | |
| 391 payments::mojom::blink::AndroidPayTokenization::UNSPECIFIED; | |
| 392 } | |
| 393 } | |
| 394 | |
| 395 if (tokenization.hasParameters() && | |
| 396 tokenization.parameters().v8Value()->IsObject() && | |
| 397 !tokenization.parameters().v8Value()->IsArray()) { | |
| 398 const ScriptValue& parameters = tokenization.parameters(); | |
|
Marijn Kruisselbrink
2016/11/16 19:09:13
I mentioned that record<DOMString, DOMString> or s
please use gerrit instead
2016/11/16 20:23:23
Thank you. Dictionary was exactly what I needed.
| |
| 399 v8::Local<v8::Array> keys( | |
| 400 parameters.v8Value().As<v8::Object>()->GetOwnPropertyNames()); | |
| 401 output->parameters.resize(keys->Length()); | |
| 402 for (uint32_t i = 0; i < keys->Length(); ++i) { | |
| 403 v8::Local<v8::Value> key(keys->Get(i)); | |
| 404 if (key->IsString()) { | |
| 405 v8::TryCatch tryCatch(parameters.isolate()); | |
| 406 v8::Local<v8::Value> value = | |
| 407 parameters.v8Value().As<v8::Object>()->Get(key); | |
| 408 if (!tryCatch.HasCaught() && value->IsString()) { | |
| 409 output->parameters[i] = | |
| 410 payments::mojom::blink::AndroidPayTokenizationParameter::New(); | |
| 411 | |
| 412 v8::String::Utf8Value utf8Key(key); | |
| 413 output->parameters[i]->key = String(*utf8Key, utf8Key.length()); | |
| 414 | |
| 415 v8::String::Utf8Value utf8Value(value); | |
| 416 output->parameters[i]->value = | |
| 417 String(*utf8Value, utf8Value.length()); | |
| 418 } | |
| 419 } | |
| 420 } | |
| 421 } | |
| 422 } | |
| 423 } | |
| 424 | |
| 352 void validateAndConvertPaymentMethodData( | 425 void validateAndConvertPaymentMethodData( |
| 353 const HeapVector<PaymentMethodData>& paymentMethodDataVector, | 426 const HeapVector<PaymentMethodData>& input, |
| 354 Vector<PaymentRequest::MethodData>* methodData, | 427 Vector<payments::mojom::blink::PaymentMethodDataPtr>& output, |
| 355 ExceptionState& exceptionState) { | 428 ExceptionState& exceptionState) { |
| 356 if (paymentMethodDataVector.isEmpty()) { | 429 if (input.isEmpty()) { |
| 357 exceptionState.throwTypeError( | 430 exceptionState.throwTypeError( |
| 358 "Must specify at least one payment method identifier"); | 431 "Must specify at least one payment method identifier"); |
| 359 return; | 432 return; |
| 360 } | 433 } |
| 361 | 434 |
| 362 for (const auto& paymentMethodData : paymentMethodDataVector) { | 435 output.resize(input.size()); |
| 436 for (size_t i = 0; i < input.size(); ++i) { | |
| 437 const auto& paymentMethodData = input[i]; | |
| 363 if (paymentMethodData.supportedMethods().isEmpty()) { | 438 if (paymentMethodData.supportedMethods().isEmpty()) { |
| 364 exceptionState.throwTypeError( | 439 exceptionState.throwTypeError( |
| 365 "Must specify at least one payment method identifier"); | 440 "Must specify at least one payment method identifier"); |
| 366 return; | 441 return; |
| 367 } | 442 } |
| 368 | 443 |
| 369 String stringifiedData = ""; | 444 String stringifiedData = ""; |
| 370 if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) { | 445 if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) { |
| 371 if (!paymentMethodData.data().v8Value()->IsObject() || | 446 if (!paymentMethodData.data().v8Value()->IsObject() || |
| 372 paymentMethodData.data().v8Value()->IsArray()) { | 447 paymentMethodData.data().v8Value()->IsArray()) { |
| 373 exceptionState.throwTypeError( | 448 exceptionState.throwTypeError( |
| 374 "Data should be a JSON-serializable object"); | 449 "Data should be a JSON-serializable object"); |
| 375 return; | 450 return; |
| 376 } | 451 } |
| 377 | 452 |
| 378 v8::Local<v8::String> value; | 453 v8::Local<v8::String> value; |
| 379 if (!v8::JSON::Stringify( | 454 if (!v8::JSON::Stringify( |
| 380 paymentMethodData.data().context(), | 455 paymentMethodData.data().context(), |
| 381 paymentMethodData.data().v8Value().As<v8::Object>()) | 456 paymentMethodData.data().v8Value().As<v8::Object>()) |
| 382 .ToLocal(&value)) { | 457 .ToLocal(&value)) { |
| 383 exceptionState.throwTypeError( | 458 exceptionState.throwTypeError( |
| 384 "Unable to parse payment method specific data"); | 459 "Unable to parse payment method specific data"); |
| 385 return; | 460 return; |
| 386 } | 461 } |
| 387 stringifiedData = | 462 stringifiedData = |
| 388 v8StringToWebCoreString<String>(value, DoNotExternalize); | 463 v8StringToWebCoreString<String>(value, DoNotExternalize); |
| 389 } | 464 } |
| 390 methodData->append(PaymentRequest::MethodData( | 465 |
| 391 paymentMethodData.supportedMethods(), stringifiedData)); | 466 output[i] = payments::mojom::blink::PaymentMethodData::New(); |
| 467 output[i]->supported_methods = paymentMethodData.supportedMethods(); | |
| 468 output[i]->stringified_data = stringifiedData; | |
| 469 maybeSetAndroidPayMethodata(paymentMethodData.data(), output[i]); | |
| 392 } | 470 } |
| 393 } | 471 } |
| 394 | 472 |
| 395 String getSelectedShippingOption(const PaymentDetails& details) { | 473 String getSelectedShippingOption(const PaymentDetails& details) { |
| 396 String result; | 474 String result; |
| 397 if (!details.hasShippingOptions()) | 475 if (!details.hasShippingOptions()) |
| 398 return result; | 476 return result; |
| 399 | 477 |
| 400 for (int i = details.shippingOptions().size() - 1; i >= 0; --i) { | 478 for (int i = details.shippingOptions().size() - 1; i >= 0; --i) { |
| 401 if (details.shippingOptions()[i].hasSelected() && | 479 if (details.shippingOptions()[i].hasSelected() && |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 448 if (ownerElement && isHTMLIFrameElement(ownerElement)) { | 526 if (ownerElement && isHTMLIFrameElement(ownerElement)) { |
| 449 HTMLIFrameElement* iframe = toHTMLIFrameElement(ownerElement); | 527 HTMLIFrameElement* iframe = toHTMLIFrameElement(ownerElement); |
| 450 if (HTMLIFrameElementPayments::from(*iframe).allowPaymentRequest(*iframe)) | 528 if (HTMLIFrameElementPayments::from(*iframe).allowPaymentRequest(*iframe)) |
| 451 return allowedToUsePaymentRequest(frame->tree().parent()); | 529 return allowedToUsePaymentRequest(frame->tree().parent()); |
| 452 } | 530 } |
| 453 | 531 |
| 454 // 4. Return false. | 532 // 4. Return false. |
| 455 return false; | 533 return false; |
| 456 } | 534 } |
| 457 | 535 |
| 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 | 536 } // namespace |
| 473 | 537 |
| 474 PaymentRequest* PaymentRequest::create( | 538 PaymentRequest* PaymentRequest::create( |
| 475 ScriptState* scriptState, | 539 ScriptState* scriptState, |
| 476 const HeapVector<PaymentMethodData>& methodData, | 540 const HeapVector<PaymentMethodData>& methodData, |
| 477 const PaymentDetails& details, | 541 const PaymentDetails& details, |
| 478 ExceptionState& exceptionState) { | 542 ExceptionState& exceptionState) { |
| 479 return new PaymentRequest(scriptState, methodData, details, PaymentOptions(), | 543 return new PaymentRequest(scriptState, methodData, details, PaymentOptions(), |
| 480 exceptionState); | 544 exceptionState); |
| 481 } | 545 } |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 632 PaymentRequest::PaymentRequest(ScriptState* scriptState, | 696 PaymentRequest::PaymentRequest(ScriptState* scriptState, |
| 633 const HeapVector<PaymentMethodData>& methodData, | 697 const HeapVector<PaymentMethodData>& methodData, |
| 634 const PaymentDetails& details, | 698 const PaymentDetails& details, |
| 635 const PaymentOptions& options, | 699 const PaymentOptions& options, |
| 636 ExceptionState& exceptionState) | 700 ExceptionState& exceptionState) |
| 637 : ContextLifecycleObserver(scriptState->getExecutionContext()), | 701 : ContextLifecycleObserver(scriptState->getExecutionContext()), |
| 638 ActiveScriptWrappable(this), | 702 ActiveScriptWrappable(this), |
| 639 m_options(options), | 703 m_options(options), |
| 640 m_clientBinding(this), | 704 m_clientBinding(this), |
| 641 m_completeTimer(this, &PaymentRequest::onCompleteTimeout) { | 705 m_completeTimer(this, &PaymentRequest::onCompleteTimeout) { |
| 642 Vector<MethodData> validatedMethodData; | 706 Vector<payments::mojom::blink::PaymentMethodDataPtr> validatedMethodData; |
| 643 validateAndConvertPaymentMethodData(methodData, &validatedMethodData, | 707 validateAndConvertPaymentMethodData(methodData, validatedMethodData, |
| 644 exceptionState); | 708 exceptionState); |
| 645 if (exceptionState.hadException()) | 709 if (exceptionState.hadException()) |
| 646 return; | 710 return; |
| 647 | 711 |
| 648 if (!scriptState->getExecutionContext()->isSecureContext()) { | 712 if (!scriptState->getExecutionContext()->isSecureContext()) { |
| 649 exceptionState.throwSecurityError("Must be in a secure context"); | 713 exceptionState.throwSecurityError("Must be in a secure context"); |
| 650 return; | 714 return; |
| 651 } | 715 } |
| 652 | 716 |
| 653 if (!allowedToUsePaymentRequest(scriptState->domWindow()->frame())) { | 717 if (!allowedToUsePaymentRequest(scriptState->domWindow()->frame())) { |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 672 m_shippingType = getValidShippingType(m_options.shippingType()); | 736 m_shippingType = getValidShippingType(m_options.shippingType()); |
| 673 } | 737 } |
| 674 | 738 |
| 675 scriptState->domWindow()->frame()->interfaceProvider()->getInterface( | 739 scriptState->domWindow()->frame()->interfaceProvider()->getInterface( |
| 676 mojo::GetProxy(&m_paymentProvider)); | 740 mojo::GetProxy(&m_paymentProvider)); |
| 677 m_paymentProvider.set_connection_error_handler(convertToBaseCallback( | 741 m_paymentProvider.set_connection_error_handler(convertToBaseCallback( |
| 678 WTF::bind(&PaymentRequest::OnError, wrapWeakPersistent(this), | 742 WTF::bind(&PaymentRequest::OnError, wrapWeakPersistent(this), |
| 679 payments::mojom::blink::PaymentErrorReason::UNKNOWN))); | 743 payments::mojom::blink::PaymentErrorReason::UNKNOWN))); |
| 680 m_paymentProvider->Init( | 744 m_paymentProvider->Init( |
| 681 m_clientBinding.CreateInterfacePtrAndBind(), | 745 m_clientBinding.CreateInterfacePtrAndBind(), |
| 682 ConvertPaymentMethodData(validatedMethodData), | 746 std::move(validatedMethodData), |
| 683 maybeKeepShippingOptions( | 747 maybeKeepShippingOptions( |
| 684 payments::mojom::blink::PaymentDetails::From(details), | 748 payments::mojom::blink::PaymentDetails::From(details), |
| 685 keepShippingOptions && m_options.requestShipping()), | 749 keepShippingOptions && m_options.requestShipping()), |
| 686 payments::mojom::blink::PaymentOptions::From(m_options)); | 750 payments::mojom::blink::PaymentOptions::From(m_options)); |
| 687 } | 751 } |
| 688 | 752 |
| 689 void PaymentRequest::contextDestroyed() { | 753 void PaymentRequest::contextDestroyed() { |
| 690 clearResolversAndCloseMojoConnection(); | 754 clearResolversAndCloseMojoConnection(); |
| 691 } | 755 } |
| 692 | 756 |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 858 m_completeTimer.stop(); | 922 m_completeTimer.stop(); |
| 859 m_completeResolver.clear(); | 923 m_completeResolver.clear(); |
| 860 m_showResolver.clear(); | 924 m_showResolver.clear(); |
| 861 m_abortResolver.clear(); | 925 m_abortResolver.clear(); |
| 862 if (m_clientBinding.is_bound()) | 926 if (m_clientBinding.is_bound()) |
| 863 m_clientBinding.Close(); | 927 m_clientBinding.Close(); |
| 864 m_paymentProvider.reset(); | 928 m_paymentProvider.reset(); |
| 865 } | 929 } |
| 866 | 930 |
| 867 } // namespace blink | 931 } // namespace blink |
| OLD | NEW |