summaryrefslogtreecommitdiff
path: root/chromium/components/payments
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-07-16 11:45:35 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-07-17 08:59:23 +0000
commit552906b0f222c5d5dd11b9fd73829d510980461a (patch)
tree3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/components/payments
parent1b05827804eaf047779b597718c03e7d38344261 (diff)
downloadqtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/payments')
-rw-r--r--chromium/components/payments/OWNERS7
-rw-r--r--chromium/components/payments/content/OWNERS7
-rw-r--r--chromium/components/payments/content/android/BUILD.gn25
-rw-r--r--chromium/components/payments/content/android/OWNERS3
-rw-r--r--chromium/components/payments/content/android/byte_buffer_helper.cc7
-rw-r--r--chromium/components/payments/content/android/byte_buffer_helper.h36
-rw-r--r--chromium/components/payments/content/android/error_message_util.cc33
-rw-r--r--chromium/components/payments/content/android/java/src/org/chromium/components/payments/Address.java66
-rw-r--r--chromium/components/payments/content/android/java/src/org/chromium/components/payments/ErrorMessageUtil.java33
-rw-r--r--chromium/components/payments/content/android/java/src/org/chromium/components/payments/PayerData.java40
-rw-r--r--chromium/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestDownloader.java71
-rw-r--r--chromium/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestParser.java15
-rw-r--r--chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/IsReadyToPayServiceHelper.java148
-rw-r--r--chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java547
-rw-r--r--chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperType.java115
-rw-r--r--chromium/components/payments/content/android/java_templates/ErrorStrings.java.tmpl2
-rw-r--r--chromium/components/payments/content/android/payment_manifest_downloader_android.cc21
-rw-r--r--chromium/components/payments/content/android/payment_manifest_downloader_android.h3
-rw-r--r--chromium/components/payments/content/android/payment_manifest_parser_android.cc3
-rw-r--r--chromium/components/payments/content/android/payment_manifest_parser_android.h1
-rw-r--r--chromium/components/payments/content/autofill_payment_app_factory.cc25
-rw-r--r--chromium/components/payments/content/icon/BUILD.gn4
-rw-r--r--chromium/components/payments/content/installable_payment_app_crawler.cc76
-rw-r--r--chromium/components/payments/content/installable_payment_app_crawler.h25
-rw-r--r--chromium/components/payments/content/manifest_verifier.cc10
-rw-r--r--chromium/components/payments/content/manifest_verifier.h10
-rw-r--r--chromium/components/payments/content/payment_app_factory.h33
-rw-r--r--chromium/components/payments/content/payment_app_service.cc8
-rw-r--r--chromium/components/payments/content/payment_app_service.h15
-rw-r--r--chromium/components/payments/content/payment_app_unittest.cc199
-rw-r--r--chromium/components/payments/content/payment_event_response_util.cc39
-rw-r--r--chromium/components/payments/content/payment_event_response_util.h5
-rw-r--r--chromium/components/payments/content/payment_manifest_web_data_service.cc27
-rw-r--r--chromium/components/payments/content/payment_manifest_web_data_service.h3
-rw-r--r--chromium/components/payments/content/payment_request.cc58
-rw-r--r--chromium/components/payments/content/payment_request.h22
-rw-r--r--chromium/components/payments/content/payment_request_converter.cc18
-rw-r--r--chromium/components/payments/content/payment_request_converter.h4
-rw-r--r--chromium/components/payments/content/payment_request_spec.cc22
-rw-r--r--chromium/components/payments/content/payment_request_spec.h6
-rw-r--r--chromium/components/payments/content/payment_request_state.cc69
-rw-r--r--chromium/components/payments/content/payment_request_state.h27
-rw-r--r--chromium/components/payments/content/payment_request_state_unittest.cc10
-rw-r--r--chromium/components/payments/content/payment_response_helper_unittest.cc86
-rw-r--r--chromium/components/payments/content/service_worker_payment_app.cc57
-rw-r--r--chromium/components/payments/content/service_worker_payment_app.h22
-rw-r--r--chromium/components/payments/content/service_worker_payment_app_factory.cc39
-rw-r--r--chromium/components/payments/content/service_worker_payment_app_finder.cc66
-rw-r--r--chromium/components/payments/content/service_worker_payment_app_finder.h23
-rw-r--r--chromium/components/payments/content/service_worker_payment_app_finder_unittest.cc54
-rw-r--r--chromium/components/payments/content/service_worker_payment_app_unittest.cc35
-rw-r--r--chromium/components/payments/content/utility/BUILD.gn12
-rw-r--r--chromium/components/payments/content/utility/payment_manifest_parser.cc42
-rw-r--r--chromium/components/payments/content/utility/payment_manifest_parser.h17
-rw-r--r--chromium/components/payments/content/utility/payment_manifest_parser_unittest.cc29
-rw-r--r--chromium/components/payments/content/utility/payment_method_manifest_parser_fuzzer.cc4
-rw-r--r--chromium/components/payments/core/BUILD.gn103
-rw-r--r--chromium/components/payments/core/OWNERS4
-rw-r--r--chromium/components/payments/core/autofill_payment_app.cc50
-rw-r--r--chromium/components/payments/core/autofill_payment_app.h21
-rw-r--r--chromium/components/payments/core/autofill_payment_app_unittest.cc81
-rw-r--r--chromium/components/payments/core/error_message_util.cc35
-rw-r--r--chromium/components/payments/core/error_message_util.h19
-rw-r--r--chromium/components/payments/core/error_strings.cc1
-rw-r--r--chromium/components/payments/core/error_strings.h3
-rw-r--r--chromium/components/payments/core/features.cc4
-rw-r--r--chromium/components/payments/core/features.h5
-rw-r--r--chromium/components/payments/core/journey_logger.cc42
-rw-r--r--chromium/components/payments/core/journey_logger.h20
-rw-r--r--chromium/components/payments/core/method_strings.cc1
-rw-r--r--chromium/components/payments/core/method_strings.h3
-rw-r--r--chromium/components/payments/core/native_error_strings.cc77
-rw-r--r--chromium/components/payments/core/native_error_strings.h79
-rw-r--r--chromium/components/payments/core/payment_app.cc56
-rw-r--r--chromium/components/payments/core/payment_app.h26
-rw-r--r--chromium/components/payments/core/payment_manifest_downloader.cc209
-rw-r--r--chromium/components/payments/core/payment_manifest_downloader.h74
-rw-r--r--chromium/components/payments/core/payment_manifest_downloader_unittest.cc383
-rw-r--r--chromium/components/payments/core/payment_method_data.cc44
-rw-r--r--chromium/components/payments/core/payment_method_data.h1
-rw-r--r--chromium/components/payments/core/payment_method_data_unittest.cc17
-rw-r--r--chromium/components/payments/core/payment_request_data_util.cc29
-rw-r--r--chromium/components/payments/core/payment_request_data_util.h8
-rw-r--r--chromium/components/payments/core/payment_request_data_util_unittest.cc39
-rw-r--r--chromium/components/payments/core/strings_util.cc64
-rw-r--r--chromium/components/payments/core/strings_util.h13
-rw-r--r--chromium/components/payments/core/strings_util_unittest.cc98
-rw-r--r--chromium/components/payments/core/test_payment_manifest_downloader.cc9
-rw-r--r--chromium/components/payments/core/test_payment_manifest_downloader.h5
-rw-r--r--chromium/components/payments/mojom/BUILD.gn4
90 files changed, 2726 insertions, 1285 deletions
diff --git a/chromium/components/payments/OWNERS b/chromium/components/payments/OWNERS
index 35f24cd7f6f..05079eaab8e 100644
--- a/chromium/components/payments/OWNERS
+++ b/chromium/components/payments/OWNERS
@@ -1,7 +1,10 @@
-gogerald@chromium.org
+# TEAM: payments-dev@chromium.org
+# COMPONENT: UI>Browser>Payments
+
rouslan@chromium.org
danyao@chromium.org
maxlg@chromium.org
sahel@chromium.org
-# COMPONENT: UI>Browser>Payments
+# Emeritus
+gogerald@chromium.org
diff --git a/chromium/components/payments/content/OWNERS b/chromium/components/payments/content/OWNERS
deleted file mode 100644
index b315c002aac..00000000000
--- a/chromium/components/payments/content/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-per-file payment_response_helper*=sebsg@chromium.org
-
-per-file payment_manifest_web_data_service*=gogerald@chromium.org
-per-file payment_method_manifest_table*=gogerald@chromium.org
-per-file web_app_manifest_section_table*=gogerald@chromium.org
-
-# COMPONENT: UI>Browser>Payments
diff --git a/chromium/components/payments/content/android/BUILD.gn b/chromium/components/payments/content/android/BUILD.gn
index 3ec052c341c..b7e430a2eec 100644
--- a/chromium/components/payments/content/android/BUILD.gn
+++ b/chromium/components/payments/content/android/BUILD.gn
@@ -12,6 +12,7 @@ static_library("android") {
"byte_buffer_helper.h",
"currency_formatter_android.cc",
"currency_formatter_android.h",
+ "error_message_util.cc",
"origin_security_checker_android.cc",
"payment_handler_host.cc",
"payment_handler_host.h",
@@ -32,12 +33,15 @@ static_library("android") {
"//components/payments/core",
"//content/public/browser",
"//net",
+ "//url:gurl_android",
+ "//url:origin_android",
]
}
generate_jni("jni_headers") {
sources = [
"java/src/org/chromium/components/payments/CurrencyFormatter.java",
+ "java/src/org/chromium/components/payments/ErrorMessageUtil.java",
"java/src/org/chromium/components/payments/OriginSecurityChecker.java",
"java/src/org/chromium/components/payments/PaymentHandlerHost.java",
"java/src/org/chromium/components/payments/PaymentManifestDownloader.java",
@@ -49,16 +53,22 @@ generate_jni("jni_headers") {
android_library("java") {
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
- java_files = [
+ sources = [
+ "java/src/org/chromium/components/payments/Address.java",
"java/src/org/chromium/components/payments/CurrencyFormatter.java",
+ "java/src/org/chromium/components/payments/ErrorMessageUtil.java",
"java/src/org/chromium/components/payments/OriginSecurityChecker.java",
+ "java/src/org/chromium/components/payments/PayerData.java",
"java/src/org/chromium/components/payments/PaymentDetailsConverter.java",
"java/src/org/chromium/components/payments/PaymentHandlerHost.java",
"java/src/org/chromium/components/payments/PaymentManifestDownloader.java",
"java/src/org/chromium/components/payments/PaymentManifestParser.java",
"java/src/org/chromium/components/payments/PaymentValidator.java",
- "java/src/org/chromium/components/payments/WebAppManifestSection.java",
"java/src/org/chromium/components/payments/UrlUtil.java",
+ "java/src/org/chromium/components/payments/WebAppManifestSection.java",
+ "java/src/org/chromium/components/payments/intent/IsReadyToPayServiceHelper.java",
+ "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java",
+ "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperType.java",
]
deps = [
"//base:base_java",
@@ -67,21 +77,20 @@ android_library("java") {
"//content/public/android:content_java",
"//mojo/public/java:bindings_java",
"//third_party/blink/public/mojom:android_mojo_bindings_java",
+ "//url:gurl_java",
+ "//url:origin_java",
]
+ srcjar_deps = [ ":error_strings_generated_srcjar" ]
}
java_cpp_strings("error_strings_generated_srcjar") {
- sources = [
- "//components/payments/core/error_strings.cc",
- ]
+ sources = [ "//components/payments/core/error_strings.cc" ]
template = "java_templates/ErrorStrings.java.tmpl"
}
java_cpp_strings("method_strings_generated_srcjar") {
- sources = [
- "//components/payments/core/method_strings.cc",
- ]
+ sources = [ "//components/payments/core/method_strings.cc" ]
template = "java_templates/MethodStrings.java.tmpl"
}
diff --git a/chromium/components/payments/content/android/OWNERS b/chromium/components/payments/content/android/OWNERS
deleted file mode 100644
index 55cc03e0e05..00000000000
--- a/chromium/components/payments/content/android/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-gogerald@chromium.org
-
-# COMPONENT: UI>Browser>Payments
diff --git a/chromium/components/payments/content/android/byte_buffer_helper.cc b/chromium/components/payments/content/android/byte_buffer_helper.cc
index d95555719d3..bef82fc4a39 100644
--- a/chromium/components/payments/content/android/byte_buffer_helper.cc
+++ b/chromium/components/payments/content/android/byte_buffer_helper.cc
@@ -13,9 +13,10 @@ namespace android {
std::vector<uint8_t> JavaByteBufferToNativeByteVector(
JNIEnv* env,
- const base::android::JavaParamRef<jobject>& buffer) {
- jbyte* buf_in = static_cast<jbyte*>(env->GetDirectBufferAddress(buffer));
- jlong buf_size = env->GetDirectBufferCapacity(buffer);
+ const base::android::JavaRef<jobject>& buffer) {
+ jbyte* buf_in =
+ static_cast<jbyte*>(env->GetDirectBufferAddress(buffer.obj()));
+ jlong buf_size = env->GetDirectBufferCapacity(buffer.obj());
std::vector<uint8_t> result(buf_size);
memcpy(&result[0], buf_in, buf_size);
return result;
diff --git a/chromium/components/payments/content/android/byte_buffer_helper.h b/chromium/components/payments/content/android/byte_buffer_helper.h
index b72880583e1..fd21d4a2b93 100644
--- a/chromium/components/payments/content/android/byte_buffer_helper.h
+++ b/chromium/components/payments/content/android/byte_buffer_helper.h
@@ -10,6 +10,8 @@
#include <vector>
#include "base/android/scoped_java_ref.h"
+#include "base/logging.h"
+#include "mojo/public/cpp/bindings/struct_ptr.h"
namespace payments {
namespace android {
@@ -22,7 +24,39 @@ namespace android {
// &details);
std::vector<uint8_t> JavaByteBufferToNativeByteVector(
JNIEnv* env,
- const base::android::JavaParamRef<jobject>& buffer);
+ const base::android::JavaRef<jobject>& buffer);
+
+// Deserializes a java.nio.ByteBuffer into a native Mojo object. Returns true if
+// deserialization is successful.
+template <typename T>
+bool DeserializeFromJavaByteBuffer(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jbuffer,
+ mojo::StructPtr<T>* out) {
+ DCHECK(out);
+ return T::Deserialize(JavaByteBufferToNativeByteVector(env, jbuffer), out);
+}
+
+// Deserializes a java.nio.ByteBuffer[] into a vector of native Mojo objects.
+// The content of |out| is replaced. Returns true if all entries are
+// deserialized successfully.
+template <typename T>
+bool DeserializeFromJavaByteBufferArray(
+ JNIEnv* env,
+ const base::android::JavaRef<jobjectArray>& jbuffers,
+ std::vector<mojo::StructPtr<T>>* out) {
+ DCHECK(out);
+ out->clear();
+ for (const auto& jbuffer : jbuffers.ReadElements<jobject>()) {
+ mojo::StructPtr<T> data;
+ if (!DeserializeFromJavaByteBuffer(env, jbuffer, &data)) {
+ out->clear();
+ return false;
+ }
+ out->push_back(std::move(data));
+ }
+ return true;
+}
} // namespace android
} // namespace payments
diff --git a/chromium/components/payments/content/android/error_message_util.cc b/chromium/components/payments/content/android/error_message_util.cc
new file mode 100644
index 00000000000..8a3abc3253f
--- /dev/null
+++ b/chromium/components/payments/content/android/error_message_util.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <jni.h>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "components/payments/content/android/jni_headers/ErrorMessageUtil_jni.h"
+#include "components/payments/core/error_message_util.h"
+
+namespace payments {
+namespace android {
+
+// static
+base::android::ScopedJavaLocalRef<jstring>
+JNI_ErrorMessageUtil_GetNotSupportedErrorMessage(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobjectArray>& jmethods) {
+ std::vector<std::string> method_vector;
+ base::android::AppendJavaStringArrayToStringVector(env, jmethods,
+ &method_vector);
+ return base::android::ConvertUTF8ToJavaString(
+ env, GetNotSupportedErrorMessage(std::set<std::string>(
+ method_vector.begin(), method_vector.end())));
+}
+
+} // namespace android
+} // namespace payments
diff --git a/chromium/components/payments/content/android/java/src/org/chromium/components/payments/Address.java b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/Address.java
new file mode 100644
index 00000000000..6a87e1ca378
--- /dev/null
+++ b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/Address.java
@@ -0,0 +1,66 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.payments;
+
+/**
+ * An immutable class that mirrors org.chromium.payments.mojom.PaymentAddress.
+ * https://w3c.github.io/payment-request/#paymentaddress-interface
+ */
+public class Address {
+ public final String country;
+ public final String[] addressLine;
+ public final String region;
+ public final String city;
+ public final String dependentLocality;
+ public final String postalCode;
+ public final String sortingCode;
+ public final String organization;
+ public final String recipient;
+ public final String phone;
+
+ public Address() {
+ country = "";
+ addressLine = new String[0];
+ region = "";
+ city = "";
+ dependentLocality = "";
+ postalCode = "";
+ sortingCode = "";
+ organization = "";
+ recipient = "";
+ phone = "";
+ }
+
+ /**
+ * @param country The country corresponding to the address.
+ * @param addressLine The most specific part of the address. It can include, for example, a
+ * street name, a house number, apartment number, a rural delivery route, descriptive
+ * instructions, or a post office box number.
+ * @param region The top level administrative subdivision of the country. For example, this can
+ * be a state, a province, an oblast, or a prefecture.
+ * @param city The city/town portion of the address.
+ * @param dependentLocalitly The dependent locality or sublocality within a city. For example,
+ * neighborhoods, boroughs, districts, or UK dependent localities.
+ * @param postalCode The postal code or ZIP code, also known as PIN code in India.
+ * @param sortingCode The sorting code as used in, for example, France.
+ * @param organization The organization, firm, company, or institution at the address.
+ * @param recipient The name of the recipient or contact person at the address.
+ * @param phone The phone number of the recipient or contact person at the address.
+ */
+ public Address(String country, String[] addressLine, String region, String city,
+ String dependentLocality, String postalCode, String sortingCode, String organization,
+ String recipient, String phone) {
+ this.country = country;
+ this.addressLine = addressLine;
+ this.region = region;
+ this.city = city;
+ this.dependentLocality = dependentLocality;
+ this.postalCode = postalCode;
+ this.sortingCode = sortingCode;
+ this.organization = organization;
+ this.recipient = recipient;
+ this.phone = phone;
+ }
+}
diff --git a/chromium/components/payments/content/android/java/src/org/chromium/components/payments/ErrorMessageUtil.java b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/ErrorMessageUtil.java
new file mode 100644
index 00000000000..dd97c84d32f
--- /dev/null
+++ b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/ErrorMessageUtil.java
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.payments;
+
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
+
+import java.util.Set;
+
+/** Error messages for web payment. */
+@JNINamespace("payments::android")
+public class ErrorMessageUtil {
+ /**
+ * Returns the "payment method not supported" message.
+ * @param methods The payment methods that are not supported.
+ * @return The web-developer facing error message.
+ */
+ public static String getNotSupportedErrorMessage(Set<String> methods) {
+ return ErrorMessageUtilJni.get().getNotSupportedErrorMessage(
+ methods.toArray(new String[methods.size()]));
+ }
+
+ /**
+ * The interface implemented by the automatically generated JNI bindings class
+ * ErrorMessageUtilJni.
+ */
+ @NativeMethods
+ /* package */ interface Natives {
+ String getNotSupportedErrorMessage(String[] methods);
+ }
+}
diff --git a/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PayerData.java b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PayerData.java
new file mode 100644
index 00000000000..5dc1732822a
--- /dev/null
+++ b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PayerData.java
@@ -0,0 +1,40 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.payments;
+
+/**
+ * An immutable class used to bundle the payer data received from payment handlers.
+ */
+public class PayerData {
+ public final String payerName;
+ public final String payerPhone;
+ public final String payerEmail;
+ public final Address shippingAddress;
+ public final String selectedShippingOptionId;
+
+ /**
+ * @param payerName The payer's name.
+ * @param payerPhone The payer's phone number.
+ * @param payerEmail The payer's email address.
+ * @param shippingAddress The user selected shippingAddress.
+ * @param selectedShippingOptionId The user selected shipping option's identifier.
+ */
+ public PayerData(String payerName, String payerPhone, String payerEmail,
+ Address shippingAddress, String selectedShippingOptionId) {
+ this.payerName = payerName;
+ this.payerPhone = payerPhone;
+ this.payerEmail = payerEmail;
+ this.shippingAddress = shippingAddress;
+ this.selectedShippingOptionId = selectedShippingOptionId;
+ }
+
+ public PayerData() {
+ payerName = null;
+ payerPhone = null;
+ payerEmail = null;
+ shippingAddress = null;
+ selectedShippingOptionId = null;
+ }
+}
diff --git a/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestDownloader.java b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestDownloader.java
index f53e3d46ccd..681db5652fd 100644
--- a/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestDownloader.java
+++ b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestDownloader.java
@@ -4,13 +4,16 @@
package org.chromium.components.payments;
+import androidx.annotation.VisibleForTesting;
+
import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.content_public.browser.WebContents;
-
-import java.net.URI;
+import org.chromium.url.GURL;
+import org.chromium.url.Origin;
+import org.chromium.url.URI;
/**
* See comment in:
@@ -23,10 +26,17 @@ public class PaymentManifestDownloader {
/**
* Called on successful download of a payment method manifest.
*
+ * @param paymentMethodManifestUrl The URL of the payment method manifest after all
+ * redirects and the optional HTTP Link rel=payment-method-manifest header have been
+ * followed.
+ * @param paymentMethodManifestOrigin The origin of the payment method manifest after all
+ * redirects and the optional HTTP Link rel=payment-method-manifest header have been
+ * followed.
* @param content The successfully downloaded payment method manifest.
*/
@CalledByNative("ManifestDownloadCallback")
- void onPaymentMethodManifestDownloadSuccess(String content);
+ void onPaymentMethodManifestDownloadSuccess(
+ URI paymentMethodManifestUrl, Origin paymentMethodManifestOrigin, String content);
/**
* Called on successful download of a web app manifest.
@@ -68,27 +78,35 @@ public class PaymentManifestDownloader {
/**
* Downloads the payment method manifest file asynchronously.
*
- * @param methodName The payment method name that is a URI with HTTPS scheme.
- * @param callback The callback to invoke when finished downloading.
+ * @param merchantOrigin The origin of the iframe that invoked the PaymentRequest API.
+ * @param methodName The payment method name that is a URI with HTTPS scheme.
+ * @param callback The callback to invoke when finished downloading.
*/
- public void downloadPaymentMethodManifest(URI methodName, ManifestDownloadCallback callback) {
+ public void downloadPaymentMethodManifest(
+ Origin merchantOrigin, URI methodName, ManifestDownloadCallback callback) {
ThreadUtils.assertOnUiThread();
assert mNativeObject != 0;
- PaymentManifestDownloaderJni.get().downloadPaymentMethodManifest(
- mNativeObject, PaymentManifestDownloader.this, methodName, callback);
+ assert merchantOrigin != null;
+ PaymentManifestDownloaderJni.get().downloadPaymentMethodManifest(mNativeObject,
+ PaymentManifestDownloader.this, merchantOrigin, methodName, callback);
}
/**
* Downloads the web app manifest file asynchronously.
*
- * @param webAppManifestUri The web app manifest URI with HTTPS scheme.
- * @param callback The callback to invoke when finished downloading.
+ * @param paymentMethodManifestOrigin The origin of the payment method manifest that is pointing
+ * to this web app manifest.
+ * @param webAppManifestUri The web app manifest URI with HTTPS scheme.
+ * @param callback The callback to invoke when finished downloading.
*/
- public void downloadWebAppManifest(URI webAppManifestUri, ManifestDownloadCallback callback) {
+ public void downloadWebAppManifest(Origin paymentMethodManifestOrigin, URI webAppManifestUri,
+ ManifestDownloadCallback callback) {
ThreadUtils.assertOnUiThread();
assert mNativeObject != 0;
- PaymentManifestDownloaderJni.get().downloadWebAppManifest(
- mNativeObject, PaymentManifestDownloader.this, webAppManifestUri, callback);
+ assert paymentMethodManifestOrigin != null;
+ PaymentManifestDownloaderJni.get().downloadWebAppManifest(mNativeObject,
+ PaymentManifestDownloader.this, paymentMethodManifestOrigin, webAppManifestUri,
+ callback);
}
/** Destroys the native downloader. */
@@ -99,20 +117,37 @@ public class PaymentManifestDownloader {
mNativeObject = 0;
}
+ /** @return An opaque origin to be used in tests. */
+ @VisibleForTesting
+ public static Origin createOpaqueOriginForTest() {
+ return PaymentManifestDownloaderJni.get().createOpaqueOriginForTest();
+ }
+
+ /**
+ * Converts GURL to URI through string serialization. Needed because C++ knows only how to
+ * create Java GURL objects, but web payments uses URI, which is a subclass of GURL, so casting
+ * is not possible.
+ *
+ * TODO(crbug.com/1065577): Use GURL direclly everywhere in web payments.
+ *
+ * @param gurl The GURL to convert. Cannot be null. Must be valid.
+ * @return The equivalent URI.
+ */
@CalledByNative
- private static String getUriString(URI methodName) {
- return methodName.toString();
+ public static URI convertGURLToURI(GURL gurl) {
+ return URI.create(gurl.getPossiblyInvalidSpec());
}
@NativeMethods
interface Natives {
long init(WebContents webContents);
void downloadPaymentMethodManifest(long nativePaymentManifestDownloaderAndroid,
- PaymentManifestDownloader caller, URI methodName,
+ PaymentManifestDownloader caller, Origin merchantOrigin, URI methodName,
ManifestDownloadCallback callback);
void downloadWebAppManifest(long nativePaymentManifestDownloaderAndroid,
- PaymentManifestDownloader caller, URI webAppManifestUri,
- ManifestDownloadCallback callback);
+ PaymentManifestDownloader caller, Origin paymentMethodManifestOrigin,
+ URI webAppManifestUri, ManifestDownloadCallback callback);
void destroy(long nativePaymentManifestDownloaderAndroid, PaymentManifestDownloader caller);
+ Origin createOpaqueOriginForTest();
}
}
diff --git a/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestParser.java b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestParser.java
index 7853fea3d8f..be5534681f2 100644
--- a/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestParser.java
+++ b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestParser.java
@@ -9,8 +9,8 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.content_public.browser.WebContents;
+import org.chromium.url.URI;
-import java.net.URI;
import java.net.URISyntaxException;
/** Parses payment manifests in a utility process. */
@@ -76,14 +76,17 @@ public class PaymentManifestParser {
/**
* Parses the payment method manifest file asynchronously.
*
- * @param content The content to parse.
+ * @param manifestUrl The URL of the payment method manifest that is being parsed. Used for
+ * resolving the optionally relative URL of the default application.
+ * @param content The content to parse.
* @param callback The callback to invoke when finished parsing.
*/
- public void parsePaymentMethodManifest(String content, ManifestParseCallback callback) {
+ public void parsePaymentMethodManifest(
+ URI manifestUrl, String content, ManifestParseCallback callback) {
ThreadUtils.assertOnUiThread();
assert mNativePaymentManifestParserAndroid != 0;
PaymentManifestParserJni.get().parsePaymentMethodManifest(
- mNativePaymentManifestParserAndroid, content, callback);
+ mNativePaymentManifestParserAndroid, manifestUrl, content, callback);
}
/**
@@ -135,8 +138,8 @@ public class PaymentManifestParser {
interface Natives {
long createPaymentManifestParserAndroid(WebContents webContents);
void destroyPaymentManifestParserAndroid(long nativePaymentManifestParserAndroid);
- void parsePaymentMethodManifest(long nativePaymentManifestParserAndroid, String content,
- ManifestParseCallback callback);
+ void parsePaymentMethodManifest(long nativePaymentManifestParserAndroid, URI manifestUrl,
+ String content, ManifestParseCallback callback);
void parseWebAppManifest(long nativePaymentManifestParserAndroid, String content,
ManifestParseCallback callback);
}
diff --git a/chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/IsReadyToPayServiceHelper.java b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/IsReadyToPayServiceHelper.java
new file mode 100644
index 00000000000..8d8be4aee39
--- /dev/null
+++ b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/IsReadyToPayServiceHelper.java
@@ -0,0 +1,148 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.payments.intent;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import org.chromium.IsReadyToPayService;
+import org.chromium.IsReadyToPayServiceCallback;
+
+/** A helper to query the payment app's IsReadyToPay service. */
+public class IsReadyToPayServiceHelper
+ extends IsReadyToPayServiceCallback.Stub implements ServiceConnection {
+ /** The maximum number of milliseconds to wait for a response from a READY_TO_PAY service. */
+ private static final long READY_TO_PAY_TIMEOUT_MS = 400;
+ /** The maximum number of milliseconds to wait for a connection to READY_TO_PAY service. */
+ private static final long SERVICE_CONNECTION_TIMEOUT_MS = 1000;
+
+ private final Context mContext;
+
+ // This callback can be used only once, set to null after that.
+ private ResultHandler mResultHandler;
+
+ private boolean mIsServiceBindingInitiated;
+ private boolean mIsReadyToPayQueried;
+ private Handler mHandler;
+
+ /** The callback that returns the result (success or error) to the helper's caller. */
+ public interface ResultHandler {
+ /**
+ * Invoked when the service receives the response.
+ * @param isReadyToPay The service response.
+ */
+ void onIsReadyToPayServiceResponse(boolean isReadyToPay);
+
+ /** Invoked when the service has any error. */
+ void onIsReadyToPayServiceError();
+ }
+
+ /**
+ * The constructor starts the IsReadyToPay service. The result would be returned asynchronously
+ * with one callback.
+ * @param context The application context. Should not be null.
+ * @param isReadyToPayIntent The IsReaddyToPay intent created by {@link
+ * WebPaymentIntentHelper#createIsReadyToPayIntent}. Should not be null.
+ * @param resultHandler Invoked when the service's result is known. Should not be null.
+ */
+ public IsReadyToPayServiceHelper(
+ Context context, Intent isReadyToPayIntent, ResultHandler resultHandler) {
+ assert context != null;
+ assert isReadyToPayIntent != null;
+ assert resultHandler != null;
+ mContext = context;
+ mResultHandler = resultHandler;
+ mHandler = new Handler();
+ try {
+ // This method returns "true if the system is in the process of bringing up a
+ // service that your client has permission to bind to; false if the system couldn't
+ // find the service or if your client doesn't have permission to bind to it. If this
+ // value is true, you should later call unbindService(ServiceConnection) to release
+ // the connection."
+ // https://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent,%20android.content.ServiceConnection,%20int)
+ mIsServiceBindingInitiated = mContext.bindService(
+ isReadyToPayIntent, /*serviceConnection=*/this, Context.BIND_AUTO_CREATE);
+ } catch (SecurityException e) {
+ // Intentionally blank, so mIsServiceBindingInitiated is false.
+ }
+
+ if (!mIsServiceBindingInitiated) {
+ reportError();
+ return;
+ }
+
+ mHandler.postDelayed(() -> {
+ if (!mIsReadyToPayQueried) reportError();
+ }, SERVICE_CONNECTION_TIMEOUT_MS);
+ }
+
+ // ServiceConnection:
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ // Timeout could cause the null.
+ if (mResultHandler == null) return;
+
+ IsReadyToPayService isReadyToPayService = IsReadyToPayService.Stub.asInterface(service);
+ if (isReadyToPayService == null) {
+ reportError();
+ return;
+ }
+
+ mIsReadyToPayQueried = true;
+ try {
+ isReadyToPayService.isReadyToPay(/*callback=*/this);
+ } catch (Throwable e) {
+ // Many undocumented exceptions are not caught in the remote Service but passed on
+ // to the Service caller, see writeException in Parcel.java.
+ reportError();
+ return;
+ }
+ mHandler.postDelayed(this::reportError, READY_TO_PAY_TIMEOUT_MS);
+ }
+
+ // "Called when a connection to the Service has been lost. This typically happens
+ // when the process hosting the service has crashed or been killed. This does not
+ // remove the ServiceConnection itself -- this binding to the service will remain
+ // active, and you will receive a call to onServiceConnected(ComponentName, IBinder)
+ // when the Service is next running."
+ // https://developer.android.com/reference/android/content/ServiceConnection.html#onServiceDisconnected(android.content.ComponentName)
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // Do not wait for the service to restart.
+ reportError();
+ }
+
+ // IsReadyToPayServiceCallback.Stub:
+ @Override
+ public void handleIsReadyToPay(boolean isReadyToPay) throws RemoteException {
+ if (mResultHandler == null) return;
+ mResultHandler.onIsReadyToPayServiceResponse(isReadyToPay);
+ mResultHandler = null;
+ destroy();
+ }
+
+ private void reportError() {
+ if (mResultHandler == null) return;
+ mResultHandler.onIsReadyToPayServiceError();
+ mResultHandler = null;
+ destroy();
+ }
+
+ /** Clean up the resources that this helper has created. */
+ private void destroy() {
+ if (mIsServiceBindingInitiated) {
+ // ServiceConnection "parameter must not be null."
+ // https://developer.android.com/reference/android/content/Context.html#unbindService(android.content.ServiceConnection)
+ mContext.unbindService(/*serviceConnection=*/this);
+ mIsServiceBindingInitiated = false;
+ }
+ mHandler.removeCallbacksAndMessages(null);
+ }
+}
diff --git a/chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java
new file mode 100644
index 00000000000..5b268616e3d
--- /dev/null
+++ b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java
@@ -0,0 +1,547 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.payments.intent;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.JsonWriter;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.components.payments.Address;
+import org.chromium.components.payments.ErrorStrings;
+import org.chromium.components.payments.PayerData;
+import org.chromium.components.payments.intent.WebPaymentIntentHelperType.PaymentCurrencyAmount;
+import org.chromium.components.payments.intent.WebPaymentIntentHelperType.PaymentDetailsModifier;
+import org.chromium.components.payments.intent.WebPaymentIntentHelperType.PaymentItem;
+import org.chromium.components.payments.intent.WebPaymentIntentHelperType.PaymentMethodData;
+import org.chromium.components.payments.intent.WebPaymentIntentHelperType.PaymentOptions;
+import org.chromium.components.payments.intent.WebPaymentIntentHelperType.PaymentShippingOption;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * The helper that handles intent for AndroidPaymentApp.
+ */
+public class WebPaymentIntentHelper {
+ /** The action name for the Pay Intent. */
+ public static final String ACTION_PAY = "org.chromium.intent.action.PAY";
+
+ // Freshest parameters sent to the payment app.
+ public static final String EXTRA_CERTIFICATE = "certificate";
+ public static final String EXTRA_MERCHANT_NAME = "merchantName";
+ public static final String EXTRA_METHOD_DATA = "methodData";
+ public static final String EXTRA_METHOD_NAMES = "methodNames";
+ public static final String EXTRA_MODIFIERS = "modifiers";
+ public static final String EXTRA_PAYMENT_REQUEST_ID = "paymentRequestId";
+ public static final String EXTRA_PAYMENT_REQUEST_ORIGIN = "paymentRequestOrigin";
+ public static final String EXTRA_TOP_CERTIFICATE_CHAIN = "topLevelCertificateChain";
+ public static final String EXTRA_TOP_ORIGIN = "topLevelOrigin";
+ public static final String EXTRA_TOTAL = "total";
+ public static final String EXTRA_PAYMENT_OPTIONS = "paymentOptions";
+ public static final String EXTRA_SHIPPING_OPTIONS = "shippingOptions";
+ public static final String EXTRA_SHIPPING_OPTION_ID = "shippingOptionId";
+ public static final String EXTRA_SHIPPING_OPTION_LABEL = "label";
+ public static final String EXTRA_SHIPPING_OPTION_SELECTED = "selected";
+ public static final String EXTRA_SHIPPING_OPTION_AMOUNT_CURRENCY = "amountCurrency";
+ public static final String EXTRA_SHIPPING_OPTION_AMOUNT_VALUE = "amountValue";
+
+ // Deprecated parameters sent to the payment app for backward compatibility.
+ public static final String EXTRA_DEPRECATED_CERTIFICATE_CHAIN = "certificateChain";
+ public static final String EXTRA_DEPRECATED_DATA = "data";
+ public static final String EXTRA_DEPRECATED_DATA_MAP = "dataMap";
+ public static final String EXTRA_DEPRECATED_DETAILS = "details";
+ public static final String EXTRA_DEPRECATED_ID = "id";
+ public static final String EXTRA_DEPRECATED_IFRAME_ORIGIN = "iframeOrigin";
+ public static final String EXTRA_DEPRECATED_METHOD_NAME = "methodName";
+ public static final String EXTRA_DEPRECATED_ORIGIN = "origin";
+
+ // Response from the payment app.
+ public static final String EXTRA_DEPRECATED_RESPONSE_INSTRUMENT_DETAILS = "instrumentDetails";
+ public static final String EXTRA_RESPONSE_DETAILS = "details";
+ public static final String EXTRA_RESPONSE_METHOD_NAME = "methodName";
+ public static final String EXTRA_RESPONSE_PAYER_NAME = "payerName";
+ public static final String EXTRA_RESPONSE_PAYER_EMAIL = "payerEmail";
+ public static final String EXTRA_RESPONSE_PAYER_PHONE = "payerPhone";
+
+ // Shipping address parsable and its fields, used in payment response and shippingAddressChange.
+ public static final String EXTRA_SHIPPING_ADDRESS = "shippingAddress";
+ public static final String EXTRA_ADDRESS_COUNTRY = "country";
+ public static final String EXTRA_ADDRESS_LINES = "addressLines";
+ public static final String EXTRA_ADDRESS_REGION = "region";
+ public static final String EXTRA_ADDRESS_CITY = "city";
+ public static final String EXTRA_ADDRESS_DEPENDENT_LOCALITY = "dependentLocality";
+ public static final String EXTRA_ADDRESS_POSTAL_CODE = "postalCode";
+ public static final String EXTRA_ADDRESS_SORTING_CODE = "sortingCode";
+ public static final String EXTRA_ADDRESS_ORGANIZATION = "organization";
+ public static final String EXTRA_ADDRESS_RECIPIENT = "recipient";
+ public static final String EXTRA_ADDRESS_PHONE = "phone";
+
+ private static final String EMPTY_JSON_DATA = "{}";
+
+ /** Invoked to report error for {@link #parsePaymentResponse}. */
+ public interface PaymentErrorCallback {
+ /** @param errorString The string that explains the error. */
+ void onPaymentError(String errorString);
+ }
+
+ /** Invoked to receive parsed data for {@link #parsePaymentResponse}. */
+ public interface PaymentSuccessCallback {
+ /**
+ * @param methodName The method name parsed from the intent response.
+ * @param details The instrument details parsed from the intent response.
+ * @param payerData The payer data parsed from the intent response.
+ */
+ void onPaymentSuccess(String methodName, String details, PayerData payerData);
+ }
+
+ /**
+ * Parse the Payment Intent response.
+ * @param resultCode Result code of the requested intent.
+ * @param data The intent response data.
+ * @param requestedPaymentOptions The merchant required payment options. This is used to
+ * populate relevant fields in payerData.
+ * @param errorCallback Callback to handle parsing errors. Invoked synchronously.
+ * @param successCallback Callback to receive the parsed data. Invoked synchronously.
+ **/
+ public static void parsePaymentResponse(int resultCode, Intent data,
+ PaymentOptions requestedPaymentOptions, PaymentErrorCallback errorCallback,
+ PaymentSuccessCallback successCallback) {
+ if (data == null) {
+ errorCallback.onPaymentError(ErrorStrings.MISSING_INTENT_DATA);
+ } else if (data.getExtras() == null) {
+ errorCallback.onPaymentError(ErrorStrings.MISSING_INTENT_EXTRAS);
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ errorCallback.onPaymentError(ErrorStrings.RESULT_CANCELED);
+ } else if (resultCode != Activity.RESULT_OK) {
+ errorCallback.onPaymentError(String.format(
+ Locale.US, ErrorStrings.UNRECOGNIZED_ACTIVITY_RESULT, resultCode));
+ } else {
+ // TODO(https://crbug.com/1026667): Validate presence of required fields and call
+ // errorCallback to make error handling consistent with Desktop.
+ String details = data.getExtras().getString(EXTRA_RESPONSE_DETAILS);
+ if (details == null) {
+ details = data.getExtras().getString(EXTRA_DEPRECATED_RESPONSE_INSTRUMENT_DETAILS);
+ }
+ if (details == null) details = EMPTY_JSON_DATA;
+ String methodName = data.getExtras().getString(EXTRA_RESPONSE_METHOD_NAME);
+ if (methodName == null) methodName = "";
+
+ PayerData payerData;
+ if (requestedPaymentOptions != null) {
+ // Create payer data based on requested payment options.
+ Address shippingAddress = !requestedPaymentOptions.requestShipping
+ ? new Address()
+ : new Address(getStringOrEmpty(data, EXTRA_ADDRESS_COUNTRY),
+ data.getExtras().getStringArray(EXTRA_ADDRESS_LINES),
+ getStringOrEmpty(data, EXTRA_ADDRESS_REGION),
+ getStringOrEmpty(data, EXTRA_ADDRESS_CITY),
+ getStringOrEmpty(data, EXTRA_ADDRESS_DEPENDENT_LOCALITY),
+ getStringOrEmpty(data, EXTRA_ADDRESS_POSTAL_CODE),
+ getStringOrEmpty(data, EXTRA_ADDRESS_SORTING_CODE),
+ getStringOrEmpty(data, EXTRA_ADDRESS_ORGANIZATION),
+ getStringOrEmpty(data, EXTRA_ADDRESS_RECIPIENT),
+ getStringOrEmpty(data, EXTRA_ADDRESS_PHONE));
+ payerData = new PayerData(requestedPaymentOptions.requestPayerName
+ ? data.getExtras().getString(EXTRA_RESPONSE_PAYER_NAME)
+ : "",
+ requestedPaymentOptions.requestPayerPhone
+ ? data.getExtras().getString(EXTRA_RESPONSE_PAYER_PHONE)
+ : "",
+ requestedPaymentOptions.requestPayerEmail
+ ? data.getExtras().getString(EXTRA_RESPONSE_PAYER_EMAIL)
+ : "",
+ shippingAddress,
+ requestedPaymentOptions.requestShipping
+ ? data.getExtras().getString(EXTRA_SHIPPING_OPTION_ID)
+ : "");
+ } else {
+ payerData = new PayerData();
+ }
+
+ successCallback.onPaymentSuccess(
+ /*methodName=*/methodName, /*details=*/details, payerData);
+ }
+ }
+
+ /**
+ * Create an intent to invoke a native payment app. This method throws IllegalArgumentException
+ * for invalid arguments.
+ *
+ * @param packageName The name of the package of the payment app. Only non-empty string is
+ * allowed.
+ * @param activityName The name of the payment activity in the payment app. Only non-empty
+ * string is allowed.
+ * @param id The unique identifier of the PaymentRequest. Only non-empty string is allowed.
+ * @param merchantName The name of the merchant. Cannot be null..
+ * @param schemelessOrigin The schemeless origin of this merchant. Only non-empty string is
+ * allowed.
+ * @param schemelessIframeOrigin The schemeless origin of the iframe that invoked
+ * PaymentRequest. Only non-empty string is allowed.
+ * @param certificateChain The site certificate chain of the merchant. Can be null for
+ * localhost or local file, which are secure contexts without SSL. Each byte array
+ * cannot be null.
+ * @param methodDataMap The payment-method specific data for all applicable payment methods,
+ * e.g., whether the app should be invoked in test or production, a merchant identifier,
+ * or a public key. The map and its values cannot be null. The map should have at
+ * least one entry.
+ * @param total The total amount. Cannot be null..
+ * @param displayItems The shopping cart items. OK to be null.
+ * @param modifiers The relevant payment details modifiers. OK to be null.
+ * @param paymentOptions The relevant merchant requested payment options. OK to be null.
+ * @param shippingOptions Merchant specified available shipping options. Should be non-empty
+ * when paymentOptions.requestShipping is true.
+ * @return The intent to invoke the payment app.
+ */
+ public static Intent createPayIntent(String packageName, String activityName, String id,
+ String merchantName, String schemelessOrigin, String schemelessIframeOrigin,
+ @Nullable byte[][] certificateChain, Map<String, PaymentMethodData> methodDataMap,
+ PaymentItem total, @Nullable List<PaymentItem> displayItems,
+ @Nullable Map<String, PaymentDetailsModifier> modifiers,
+ @Nullable PaymentOptions paymentOptions,
+ @Nullable List<PaymentShippingOption> shippingOptions) {
+ Intent payIntent = new Intent();
+ checkStringNotEmpty(activityName, "activityName");
+ checkStringNotEmpty(packageName, "packageName");
+ payIntent.setClassName(packageName, activityName);
+ payIntent.setAction(ACTION_PAY);
+ payIntent.putExtras(buildPayIntentExtras(id, merchantName, schemelessOrigin,
+ schemelessIframeOrigin, certificateChain, methodDataMap, total, displayItems,
+ modifiers, paymentOptions, shippingOptions));
+ return payIntent;
+ }
+
+ /**
+ * Create an intent to invoke a service that can answer "is ready to pay" query, or null of
+ * none.
+ *
+ * @param packageName The name of the package of the payment app. Only non-empty string is
+ * allowed.
+ * @param serviceName The name of the service. Only non-empty string is allowed.
+ * @param schemelessOrigin The schemeless origin of this merchant. Only non-empty string is
+ * allowed.
+ * @param schemelessIframeOrigin The schemeless origin of the iframe that invoked
+ * PaymentRequest. Only non-empty string is allowed.
+ * @param certificateChain The site certificate chain of the merchant. Can be null for localhost
+ * or local file, which are secure contexts without SSL. Each byte array
+ * cannot be null.
+ * @param methodDataMap The payment-method specific data for all applicable payment methods,
+ * e.g., whether the app should be invoked in test or production, a merchant identifier,
+ * or a public key. The map should have at least one entry.
+ * @return The intent to invoke the service.
+ */
+ public static Intent createIsReadyToPayIntent(String packageName, String serviceName,
+ String schemelessOrigin, String schemelessIframeOrigin,
+ @Nullable byte[][] certificateChain, Map<String, PaymentMethodData> methodDataMap) {
+ Intent isReadyToPayIntent = new Intent();
+ checkStringNotEmpty(serviceName, "serviceName");
+ checkStringNotEmpty(packageName, "packageName");
+ isReadyToPayIntent.setClassName(packageName, serviceName);
+
+ checkStringNotEmpty(schemelessOrigin, "schemelessOrigin");
+ checkStringNotEmpty(schemelessIframeOrigin, "schemelessIframeOrigin");
+ // certificateChain is ok to be null, left unchecked here.
+ checkNotEmpty(methodDataMap, "methodDataMap");
+ isReadyToPayIntent.putExtras(buildExtras(/*id=*/null,
+ /*merchantName=*/null, schemelessOrigin, schemelessIframeOrigin, certificateChain,
+ methodDataMap, /*total=*/null, /*displayItems=*/null, /*modifiers=*/null,
+ /*paymentOptions=*/null,
+ /*shippingOptions=*/null));
+ return isReadyToPayIntent;
+ }
+
+ private static void checkNotEmpty(Map map, String name) {
+ if (map == null || map.isEmpty()) {
+ throw new IllegalArgumentException(name + " should not be null or empty.");
+ }
+ }
+
+ private static void checkStringNotEmpty(String value, String name) {
+ if (TextUtils.isEmpty(value)) {
+ throw new IllegalArgumentException(name + " should not be null or empty.");
+ }
+ }
+ private static void checkNotNull(Object value, String name) {
+ if (value == null) throw new IllegalArgumentException(name + " should not be null.");
+ }
+
+ private static Bundle buildPayIntentExtras(String id, String merchantName,
+ String schemelessOrigin, String schemelessIframeOrigin,
+ @Nullable byte[][] certificateChain, Map<String, PaymentMethodData> methodDataMap,
+ PaymentItem total, @Nullable List<PaymentItem> displayItems,
+ @Nullable Map<String, PaymentDetailsModifier> modifiers,
+ @Nullable PaymentOptions paymentOptions,
+ @Nullable List<PaymentShippingOption> shippingOptions) {
+ // The following checks follow the order of the parameters.
+ checkStringNotEmpty(id, "id");
+ checkNotNull(merchantName, "merchantName");
+
+ checkStringNotEmpty(schemelessOrigin, "schemelessOrigin");
+ checkStringNotEmpty(schemelessIframeOrigin, "schemelessIframeOrigin");
+
+ // certificateChain is ok to be null, left unchecked here.
+
+ checkNotEmpty(methodDataMap, "methodDataMap");
+ checkNotNull(total, "total");
+
+ // displayItems is ok to be null, left unchecked here.
+ // modifiers is ok to be null, left unchecked here.
+
+ // shippingOptions should not be null when shipping is requested.
+ if (paymentOptions != null && paymentOptions.requestShipping
+ && (shippingOptions == null || shippingOptions.isEmpty())) {
+ throw new IllegalArgumentException(
+ "shippingOptions should not be null or empty when shipping is requested.");
+ }
+
+ return buildExtras(id, merchantName, schemelessOrigin, schemelessIframeOrigin,
+ certificateChain, methodDataMap, total, displayItems, modifiers, paymentOptions,
+ shippingOptions);
+ }
+
+ // id, merchantName, total are ok to be null only for {@link #createIsReadyToPayIntent}.
+ private static Bundle buildExtras(@Nullable String id, @Nullable String merchantName,
+ String schemelessOrigin, String schemelessIframeOrigin,
+ @Nullable byte[][] certificateChain, Map<String, PaymentMethodData> methodDataMap,
+ @Nullable PaymentItem total, @Nullable List<PaymentItem> displayItems,
+ @Nullable Map<String, PaymentDetailsModifier> modifiers,
+ @Nullable PaymentOptions paymentOptions,
+ @Nullable List<PaymentShippingOption> shippingOptions) {
+ Bundle extras = new Bundle();
+
+ if (id != null) extras.putString(EXTRA_PAYMENT_REQUEST_ID, id);
+
+ if (merchantName != null) extras.putString(EXTRA_MERCHANT_NAME, merchantName);
+
+ assert !TextUtils.isEmpty(schemelessOrigin);
+ extras.putString(EXTRA_TOP_ORIGIN, schemelessOrigin);
+
+ assert !TextUtils.isEmpty(schemelessIframeOrigin);
+ extras.putString(EXTRA_PAYMENT_REQUEST_ORIGIN, schemelessIframeOrigin);
+
+ Parcelable[] serializedCertificateChain = null;
+ if (certificateChain != null && certificateChain.length > 0) {
+ serializedCertificateChain = buildCertificateChain(certificateChain);
+ extras.putParcelableArray(EXTRA_TOP_CERTIFICATE_CHAIN, serializedCertificateChain);
+ }
+
+ assert methodDataMap != null && !methodDataMap.isEmpty();
+ extras.putStringArrayList(EXTRA_METHOD_NAMES, new ArrayList<>(methodDataMap.keySet()));
+
+ Bundle methodDataBundle = new Bundle();
+ for (Map.Entry<String, PaymentMethodData> methodData : methodDataMap.entrySet()) {
+ checkNotNull(methodData.getValue(), "methodDataMap's entry value");
+ methodDataBundle.putString(methodData.getKey(), methodData.getValue().stringifiedData);
+ }
+ extras.putParcelable(EXTRA_METHOD_DATA, methodDataBundle);
+
+ if (modifiers != null) {
+ extras.putString(EXTRA_MODIFIERS, serializeModifiers(modifiers.values()));
+ }
+
+ if (total != null) {
+ String serializedTotalAmount = serializeTotalAmount(total.amount);
+ extras.putString(EXTRA_TOTAL,
+ serializedTotalAmount == null ? EMPTY_JSON_DATA : serializedTotalAmount);
+ }
+
+ if (paymentOptions != null) {
+ extras.putStringArrayList(EXTRA_PAYMENT_OPTIONS, paymentOptions.asStringArrayList());
+ }
+
+ // ShippingOptions are populated only when shipping is requested.
+ if (paymentOptions != null && paymentOptions.requestShipping) {
+ Parcelable[] serializedShippingOptionList = buildShippingOptionList(shippingOptions);
+ extras.putParcelableArray(EXTRA_SHIPPING_OPTIONS, serializedShippingOptionList);
+ }
+
+ return addDeprecatedExtras(id, schemelessOrigin, schemelessIframeOrigin,
+ serializedCertificateChain, methodDataMap, methodDataBundle, total, displayItems,
+ extras);
+ }
+
+ private static Bundle addDeprecatedExtras(@Nullable String id, String schemelessOrigin,
+ String schemelessIframeOrigin, @Nullable Parcelable[] serializedCertificateChain,
+ Map<String, PaymentMethodData> methodDataMap, Bundle methodDataBundle,
+ @Nullable PaymentItem total, @Nullable List<PaymentItem> displayItems, Bundle extras) {
+ if (id != null) extras.putString(EXTRA_DEPRECATED_ID, id);
+
+ extras.putString(EXTRA_DEPRECATED_ORIGIN, schemelessOrigin);
+
+ extras.putString(EXTRA_DEPRECATED_IFRAME_ORIGIN, schemelessIframeOrigin);
+
+ if (serializedCertificateChain != null) {
+ extras.putParcelableArray(
+ EXTRA_DEPRECATED_CERTIFICATE_CHAIN, serializedCertificateChain);
+ }
+
+ String methodName = methodDataMap.entrySet().iterator().next().getKey();
+ extras.putString(EXTRA_DEPRECATED_METHOD_NAME, methodName);
+
+ PaymentMethodData firstMethodData = methodDataMap.get(methodName);
+ extras.putString(EXTRA_DEPRECATED_DATA,
+ firstMethodData == null ? EMPTY_JSON_DATA : firstMethodData.stringifiedData);
+
+ extras.putParcelable(EXTRA_DEPRECATED_DATA_MAP, methodDataBundle);
+
+ String details = deprecatedSerializeDetails(total, displayItems);
+ extras.putString(EXTRA_DEPRECATED_DETAILS, details == null ? EMPTY_JSON_DATA : details);
+
+ return extras;
+ }
+
+ private static Parcelable[] buildCertificateChain(byte[][] certificateChain) {
+ Parcelable[] result = new Parcelable[certificateChain.length];
+ for (int i = 0; i < certificateChain.length; i++) {
+ Bundle bundle = new Bundle();
+ checkNotNull(certificateChain[i], "certificateChain[" + i + "]");
+ bundle.putByteArray(EXTRA_CERTIFICATE, certificateChain[i]);
+ result[i] = bundle;
+ }
+ return result;
+ }
+
+ private static Parcelable[] buildShippingOptionList(
+ List<PaymentShippingOption> shippingOptions) {
+ Parcelable[] result = new Parcelable[shippingOptions.size()];
+ int index = 0;
+ for (PaymentShippingOption option : shippingOptions) {
+ Bundle bundle = new Bundle();
+ bundle.putString(EXTRA_SHIPPING_OPTION_ID, option.id);
+ bundle.putString(EXTRA_SHIPPING_OPTION_LABEL, option.label);
+ bundle.putString(EXTRA_SHIPPING_OPTION_AMOUNT_CURRENCY, option.amountCurrency);
+ bundle.putString(EXTRA_SHIPPING_OPTION_AMOUNT_VALUE, option.amountValue);
+ bundle.putBoolean(EXTRA_SHIPPING_OPTION_SELECTED, option.selected);
+ result[index++] = bundle;
+ }
+ return result;
+ }
+
+ private static String deprecatedSerializeDetails(
+ @Nullable PaymentItem total, @Nullable List<PaymentItem> displayItems) {
+ StringWriter stringWriter = new StringWriter();
+ JsonWriter json = new JsonWriter(stringWriter);
+ try {
+ // details {{{
+ json.beginObject();
+
+ if (total != null) {
+ // total {{{
+ json.name("total");
+ serializeTotal(total, json);
+ // }}} total
+ }
+
+ // displayitems {{{
+ if (displayItems != null) {
+ json.name("displayItems").beginArray();
+ // Do not pass any display items to the payment app.
+ json.endArray();
+ }
+ // }}} displayItems
+
+ json.endObject();
+ // }}} details
+ } catch (IOException e) {
+ return null;
+ }
+
+ return stringWriter.toString();
+ }
+
+ private static String serializeTotalAmount(PaymentCurrencyAmount totalAmount) {
+ StringWriter stringWriter = new StringWriter();
+ JsonWriter json = new JsonWriter(stringWriter);
+ try {
+ // {{{
+ json.beginObject();
+ json.name("currency").value(totalAmount.currency);
+ json.name("value").value(totalAmount.value);
+ json.endObject();
+ // }}}
+ } catch (IOException e) {
+ return null;
+ }
+ return stringWriter.toString();
+ }
+
+ private static void serializeTotal(PaymentItem item, JsonWriter json) throws IOException {
+ // item {{{
+ json.beginObject();
+ // Sanitize the total name, because the payment app does not need it to complete the
+ // transaction. Matches the behavior of:
+ // https://w3c.github.io/payment-handler/#total-attribute
+ json.name("label").value("");
+
+ // amount {{{
+ json.name("amount").beginObject();
+ json.name("currency").value(item.amount.currency);
+ json.name("value").value(item.amount.value);
+ json.endObject();
+ // }}} amount
+
+ json.endObject();
+ // }}} item
+ }
+
+ private static String serializeModifiers(Collection<PaymentDetailsModifier> modifiers) {
+ StringWriter stringWriter = new StringWriter();
+ JsonWriter json = new JsonWriter(stringWriter);
+ try {
+ json.beginArray();
+ for (PaymentDetailsModifier modifier : modifiers) {
+ checkNotNull(modifier, "PaymentDetailsModifier");
+ serializeModifier(modifier, json);
+ }
+ json.endArray();
+ } catch (IOException e) {
+ return EMPTY_JSON_DATA;
+ }
+ return stringWriter.toString();
+ }
+
+ private static void serializeModifier(PaymentDetailsModifier modifier, JsonWriter json)
+ throws IOException {
+ // {{{
+ json.beginObject();
+
+ // total {{{
+ if (modifier.total != null) {
+ json.name("total");
+ serializeTotal(modifier.total, json);
+ } else {
+ json.name("total").nullValue();
+ }
+ // }}} total
+
+ // TODO(https://crbug.com/754779): The supportedMethods field was already changed from array
+ // to string but we should keep backward-compatibility for now.
+ // supportedMethods {{{
+ json.name("supportedMethods").beginArray();
+ json.value(modifier.methodData.supportedMethod);
+ json.endArray();
+ // }}} supportedMethods
+
+ // data {{{
+ json.name("data").value(modifier.methodData.stringifiedData);
+ // }}}
+
+ json.endObject();
+ // }}}
+ }
+
+ private static String getStringOrEmpty(Intent data, String key) {
+ return data.getExtras().getString(key, /*defaultValue =*/"");
+ }
+}
diff --git a/chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperType.java b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperType.java
new file mode 100644
index 00000000000..14e17efde93
--- /dev/null
+++ b/chromium/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperType.java
@@ -0,0 +1,115 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.payments.intent;
+
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+
+/**
+ * The types that corresponds to the types in org.chromium.payments.mojom. The fields of these types
+ * are the subset of those in the mojom types. The subset is minimally selected based on the need of
+ * this package. This class should be independent of the org.chromium package.
+ *
+ * @see <a
+ * href="https://developers.google.com/web/fundamentals/payments/payment-apps-developer-guide/android-payment-apps#payment_parameters">Payment
+ * parameters</a>
+ * @see <a
+ * href="https://developers.google.com/web/fundamentals/payments/payment-apps-developer-guide/android-payment-apps#%E2%80%9Cis_ready_to_pay%E2%80%9D_parameters">“Is
+ * ready to pay” parameters</a>
+ */
+public final class WebPaymentIntentHelperType {
+ /**
+ * The class that corresponds to mojom.PaymentCurrencyAmount, with minimally required fields.
+ */
+ public static final class PaymentCurrencyAmount {
+ public final String currency;
+ public final String value;
+ public PaymentCurrencyAmount(String currency, String value) {
+ this.currency = currency;
+ this.value = value;
+ }
+ }
+
+ /** The class that corresponds mojom.PaymentItem, with minimally required fields. */
+ public static final class PaymentItem {
+ public final PaymentCurrencyAmount amount;
+ public PaymentItem(PaymentCurrencyAmount amount) {
+ this.amount = amount;
+ }
+ }
+
+ /** The class that corresponds mojom.PaymentDetailsModifier, with minimally required fields. */
+ public static final class PaymentDetailsModifier {
+ public final PaymentItem total;
+ public final PaymentMethodData methodData;
+ public PaymentDetailsModifier(PaymentItem total, PaymentMethodData methodData) {
+ this.total = total;
+ this.methodData = methodData;
+ }
+ }
+
+ /** The class that corresponds mojom.PaymentMethodData, with minimally required fields. */
+ public static final class PaymentMethodData {
+ public final String supportedMethod;
+ public final String stringifiedData;
+ public PaymentMethodData(String supportedMethod, String stringifiedData) {
+ this.supportedMethod = supportedMethod;
+ this.stringifiedData = stringifiedData;
+ }
+ }
+
+ /** The class that mirrors mojom.PaymentShippingOption. */
+ public static final class PaymentShippingOption {
+ public final String id;
+ public final String label;
+ public final String amountCurrency;
+ public final String amountValue;
+ public final boolean selected;
+ public PaymentShippingOption(String id, String label, String amountCurrency,
+ String amountValue, boolean selected) {
+ this.id = id;
+ this.label = label;
+ this.amountCurrency = amountCurrency;
+ this.amountValue = amountValue;
+ this.selected = selected;
+ }
+ }
+
+ /** The class that mirrors mojom.PaymentOptions. */
+ public static final class PaymentOptions {
+ public final boolean requestPayerName;
+ public final boolean requestPayerEmail;
+ public final boolean requestPayerPhone;
+ public final boolean requestShipping;
+ public final String shippingType;
+
+ public PaymentOptions(boolean requestPayerName, boolean requestPayerEmail,
+ boolean requestPayerPhone, boolean requestShipping, @Nullable String shippingType) {
+ this.requestPayerName = requestPayerName;
+ this.requestPayerEmail = requestPayerEmail;
+ this.requestPayerPhone = requestPayerPhone;
+ this.requestShipping = requestShipping;
+ this.shippingType = shippingType;
+ }
+
+ /**
+ * @return an ArrayList of stringified payment options. This should be an ArrayList vs a
+ * List since the |Bundle.putStringArrayList()| function used for populating
+ * "paymentOptions" in "Pay" intents accepts ArrayLists.
+ */
+ public ArrayList<String> asStringArrayList() {
+ ArrayList<String> paymentOptionList = new ArrayList<>();
+ if (requestPayerName) paymentOptionList.add("requestPayerName");
+ if (requestPayerEmail) paymentOptionList.add("requestPayerEmail");
+ if (requestPayerPhone) paymentOptionList.add("requestPayerPhone");
+ if (requestShipping) {
+ paymentOptionList.add("requestShipping");
+ paymentOptionList.add(shippingType);
+ }
+ return paymentOptionList;
+ }
+ }
+}
diff --git a/chromium/components/payments/content/android/java_templates/ErrorStrings.java.tmpl b/chromium/components/payments/content/android/java_templates/ErrorStrings.java.tmpl
index c58d0ea5eea..2ca0ff39f71 100644
--- a/chromium/components/payments/content/android/java_templates/ErrorStrings.java.tmpl
+++ b/chromium/components/payments/content/android/java_templates/ErrorStrings.java.tmpl
@@ -50,7 +50,7 @@ public abstract class ErrorStrings {{
public static final String UNRECOGNIZED_ACTIVITY_RESULT =
"Payment app returned unrecognized activity result %d.";
- public static final String MICROTRANSACTION_UI_SUPPRESSED = "Microtransaction UI suppressed.";
+ public static final String MINIMAL_UI_SUPPRESSED = "Payment minimal UI suppressed.";
// Prevent instantiation.
private ErrorStrings() {{}}
diff --git a/chromium/components/payments/content/android/payment_manifest_downloader_android.cc b/chromium/components/payments/content/android/payment_manifest_downloader_android.cc
index bc4a9ef0d42..3a2eaa1f3f1 100644
--- a/chromium/components/payments/content/android/payment_manifest_downloader_android.cc
+++ b/chromium/components/payments/content/android/payment_manifest_downloader_android.cc
@@ -15,7 +15,9 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "url/android/gurl_android.h"
#include "url/gurl.h"
+#include "url/origin.h"
namespace payments {
namespace {
@@ -40,6 +42,9 @@ class DownloadCallback {
} else {
Java_ManifestDownloadCallback_onPaymentMethodManifestDownloadSuccess(
env, jcallback_,
+ Java_PaymentManifestDownloader_convertGURLToURI(
+ env, url::GURLAndroid::FromNativeGURL(env, url_after_redirects)),
+ url::Origin::Create(url_after_redirects).CreateJavaObject(),
base::android::ConvertUTF8ToJavaString(env, content));
}
}
@@ -78,11 +83,12 @@ PaymentManifestDownloaderAndroid::~PaymentManifestDownloaderAndroid() {}
void PaymentManifestDownloaderAndroid::DownloadPaymentMethodManifest(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jobject>& jmerchant_origin,
const base::android::JavaParamRef<jobject>& juri,
const base::android::JavaParamRef<jobject>& jcallback) {
downloader_.DownloadPaymentMethodManifest(
- GURL(base::android::ConvertJavaStringToUTF8(
- env, Java_PaymentManifestDownloader_getUriString(env, juri))),
+ url::Origin::FromJavaObject(jmerchant_origin),
+ *url::GURLAndroid::ToNativeGURL(env, juri),
base::BindOnce(&DownloadCallback::OnPaymentMethodManifestDownload,
std::make_unique<DownloadCallback>(jcallback)));
}
@@ -90,11 +96,12 @@ void PaymentManifestDownloaderAndroid::DownloadPaymentMethodManifest(
void PaymentManifestDownloaderAndroid::DownloadWebAppManifest(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jobject>& jpayment_method_manifest_origin,
const base::android::JavaParamRef<jobject>& juri,
const base::android::JavaParamRef<jobject>& jcallback) {
downloader_.DownloadWebAppManifest(
- GURL(base::android::ConvertJavaStringToUTF8(
- env, Java_PaymentManifestDownloader_getUriString(env, juri))),
+ url::Origin::FromJavaObject(jpayment_method_manifest_origin),
+ *url::GURLAndroid::ToNativeGURL(env, juri),
base::BindOnce(&DownloadCallback::OnWebAppManifestDownload,
std::make_unique<DownloadCallback>(jcallback)));
}
@@ -122,4 +129,10 @@ static jlong JNI_PaymentManifestDownloader_Init(
->GetURLLoaderFactoryForBrowserProcess()));
}
+// Static free function declared and called directly from java.
+static base::android::ScopedJavaLocalRef<jobject>
+JNI_PaymentManifestDownloader_CreateOpaqueOriginForTest(JNIEnv* unused_env) {
+ return url::Origin().CreateJavaObject();
+}
+
} // namespace payments
diff --git a/chromium/components/payments/content/android/payment_manifest_downloader_android.h b/chromium/components/payments/content/android/payment_manifest_downloader_android.h
index 05a4d76e109..1d75662679f 100644
--- a/chromium/components/payments/content/android/payment_manifest_downloader_android.h
+++ b/chromium/components/payments/content/android/payment_manifest_downloader_android.h
@@ -32,12 +32,15 @@ class PaymentManifestDownloaderAndroid {
void DownloadPaymentMethodManifest(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jobject>& jmerchant_origin,
const base::android::JavaParamRef<jobject>& juri,
const base::android::JavaParamRef<jobject>& jcallback);
void DownloadWebAppManifest(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jobject>&
+ jpayment_method_manifest_origin,
const base::android::JavaParamRef<jobject>& juri,
const base::android::JavaParamRef<jobject>& jcallback);
diff --git a/chromium/components/payments/content/android/payment_manifest_parser_android.cc b/chromium/components/payments/content/android/payment_manifest_parser_android.cc
index 98abacdb4a3..4ce8749ab7f 100644
--- a/chromium/components/payments/content/android/payment_manifest_parser_android.cc
+++ b/chromium/components/payments/content/android/payment_manifest_parser_android.cc
@@ -19,6 +19,7 @@
#include "components/payments/content/developer_console_logger.h"
#include "components/payments/core/error_logger.h"
#include "content/public/browser/web_contents.h"
+#include "url/android/gurl_android.h"
#include "url/gurl.h"
namespace payments {
@@ -131,9 +132,11 @@ PaymentManifestParserAndroid::~PaymentManifestParserAndroid() {}
void PaymentManifestParserAndroid::ParsePaymentMethodManifest(
JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jmanifest_url,
const base::android::JavaParamRef<jstring>& jcontent,
const base::android::JavaParamRef<jobject>& jcallback) {
parser_.ParsePaymentMethodManifest(
+ *url::GURLAndroid::ToNativeGURL(env, jmanifest_url),
base::android::ConvertJavaStringToUTF8(env, jcontent),
base::BindOnce(&ParseCallback::OnPaymentMethodManifestParsed,
std::make_unique<ParseCallback>(jcallback)));
diff --git a/chromium/components/payments/content/android/payment_manifest_parser_android.h b/chromium/components/payments/content/android/payment_manifest_parser_android.h
index c201077a9cf..56cf43e1e85 100644
--- a/chromium/components/payments/content/android/payment_manifest_parser_android.h
+++ b/chromium/components/payments/content/android/payment_manifest_parser_android.h
@@ -25,6 +25,7 @@ class PaymentManifestParserAndroid {
void ParsePaymentMethodManifest(
JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jmanifest_url,
const base::android::JavaParamRef<jstring>& jcontent,
const base::android::JavaParamRef<jobject>& jcallback);
diff --git a/chromium/components/payments/content/autofill_payment_app_factory.cc b/chromium/components/payments/content/autofill_payment_app_factory.cc
index 04df6293989..5e39b1598f0 100644
--- a/chromium/components/payments/content/autofill_payment_app_factory.cc
+++ b/chromium/components/payments/content/autofill_payment_app_factory.cc
@@ -25,26 +25,12 @@ AutofillPaymentAppFactory::ConvertCardToPaymentAppIfSupportedNetwork(
autofill::data_util::GetPaymentRequestData(card.network())
.basic_card_issuer_network;
if (!delegate->GetSpec()->supported_card_networks_set().count(
- basic_card_network) ||
- !delegate->GetSpec()->supported_card_types_set().count(
- card.card_type())) {
+ basic_card_network)) {
return nullptr;
}
- // The total number of card types: credit, debit, prepaid, unknown.
- constexpr size_t kTotalNumberOfCardTypes = 4U;
-
- // Whether the card type (credit, debit, prepaid) matches the type that the
- // merchant has requested exactly. This should be false for unknown card
- // types, if the merchant cannot accept some card types.
- bool matches_merchant_card_type_exactly =
- card.card_type() != autofill::CreditCard::CARD_TYPE_UNKNOWN ||
- delegate->GetSpec()->supported_card_types_set().size() ==
- kTotalNumberOfCardTypes;
-
auto app = std::make_unique<AutofillPaymentApp>(
- basic_card_network, card, matches_merchant_card_type_exactly,
- delegate->GetBillingProfiles(),
+ basic_card_network, card, delegate->GetBillingProfiles(),
delegate->GetPaymentRequestDelegate()->GetApplicationLocale(),
delegate->GetPaymentRequestDelegate());
@@ -60,6 +46,13 @@ AutofillPaymentAppFactory::AutofillPaymentAppFactory()
AutofillPaymentAppFactory::~AutofillPaymentAppFactory() = default;
void AutofillPaymentAppFactory::Create(base::WeakPtr<Delegate> delegate) {
+ // No need to create autofill payment apps if native app creation is skipped
+ // because autofill payment apps are created completely by the Java factory.
+ if (delegate->SkipCreatingNativePaymentApps()) {
+ delegate->OnDoneCreatingPaymentApps();
+ return;
+ }
+
const std::vector<autofill::CreditCard*>& cards =
delegate->GetPaymentRequestDelegate()
->GetPersonalDataManager()
diff --git a/chromium/components/payments/content/icon/BUILD.gn b/chromium/components/payments/content/icon/BUILD.gn
index 6054837f849..b031c0b8bd1 100644
--- a/chromium/components/payments/content/icon/BUILD.gn
+++ b/chromium/components/payments/content/icon/BUILD.gn
@@ -10,7 +10,5 @@ jumbo_static_library("icon") {
"icon_size.h",
]
- deps = [
- "//ui/display",
- ]
+ deps = [ "//ui/display" ]
}
diff --git a/chromium/components/payments/content/installable_payment_app_crawler.cc b/chromium/components/payments/content/installable_payment_app_crawler.cc
index 485a289010f..8fe2a7570eb 100644
--- a/chromium/components/payments/content/installable_payment_app_crawler.cc
+++ b/chromium/components/payments/content/installable_payment_app_crawler.cc
@@ -15,10 +15,13 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/manifest_icon_downloader.h"
#include "content/public/browser/payment_app_provider.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/permission_type.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "third_party/blink/public/common/manifest/manifest.h"
@@ -26,19 +29,27 @@
#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
-#include "url/origin.h"
namespace payments {
// TODO(crbug.com/782270): Use cache to accelerate crawling procedure.
-// TODO(crbug.com/782270): Add integration tests for this class.
InstallablePaymentAppCrawler::InstallablePaymentAppCrawler(
+ const url::Origin& merchant_origin,
+ content::RenderFrameHost* initiator_render_frame_host,
content::WebContents* web_contents,
PaymentManifestDownloader* downloader,
PaymentManifestParser* parser,
PaymentManifestWebDataService* cache)
: WebContentsObserver(web_contents),
log_(web_contents),
+ merchant_origin_(merchant_origin),
+ initiator_frame_routing_id_(
+ initiator_render_frame_host &&
+ initiator_render_frame_host->GetProcess()
+ ? content::GlobalFrameRoutingId(
+ initiator_render_frame_host->GetProcess()->GetID(),
+ initiator_render_frame_host->GetRoutingID())
+ : content::GlobalFrameRoutingId()),
downloader_(downloader),
parser_(parser),
number_of_payment_method_manifest_to_download_(0),
@@ -79,7 +90,7 @@ void InstallablePaymentAppCrawler::Start(
number_of_payment_method_manifest_to_download_ = manifests_to_download.size();
for (const auto& url : manifests_to_download) {
downloader_->DownloadPaymentMethodManifest(
- url,
+ merchant_origin_, url,
base::BindOnce(
&InstallablePaymentAppCrawler::OnPaymentMethodManifestDownloaded,
weak_ptr_factory_.GetWeakPtr(), url));
@@ -120,7 +131,7 @@ void InstallablePaymentAppCrawler::OnPaymentMethodManifestDownloaded(
number_of_payment_method_manifest_to_parse_++;
parser_->ParsePaymentMethodManifest(
- content, base::BindOnce(
+ method_manifest_url, content, base::BindOnce(
&InstallablePaymentAppCrawler::OnPaymentMethodManifestParsed,
weak_ptr_factory_.GetWeakPtr(), method_manifest_url,
method_manifest_url_after_redirects));
@@ -172,6 +183,7 @@ void InstallablePaymentAppCrawler::OnPaymentMethodManifestParsed(
number_of_web_app_manifest_to_download_++;
downloaded_web_app_manifests_.insert(web_app_manifest_url);
downloader_->DownloadWebAppManifest(
+ url::Origin::Create(method_manifest_url_after_redirects),
web_app_manifest_url,
base::BindOnce(
&InstallablePaymentAppCrawler::OnPaymentWebAppManifestDownloaded,
@@ -222,11 +234,17 @@ void InstallablePaymentAppCrawler::OnPaymentWebAppInstallationInfo(
std::unique_ptr<std::vector<PaymentManifestParser::WebAppIcon>> icons) {
number_of_web_app_manifest_to_parse_--;
+ // Only download and decode payment app's icon if it is valid and stored.
if (CompleteAndStorePaymentWebAppInfoIfValid(
method_manifest_url, web_app_manifest_url, std::move(app_info))) {
- // Only download and decode payment app's icon if it is valid and stored.
- DownloadAndDecodeWebAppIcon(method_manifest_url, web_app_manifest_url,
- std::move(icons));
+ if (!DownloadAndDecodeWebAppIcon(method_manifest_url, web_app_manifest_url,
+ std::move(icons))) {
+ std::string error_message = base::ReplaceStringPlaceholders(
+ errors::kInvalidWebAppIcon, {web_app_manifest_url.spec()}, nullptr);
+ SetFirstError(error_message);
+ // App without a valid icon is not JIT installable.
+ installable_apps_.erase(method_manifest_url);
+ }
}
FinishCrawlingPaymentAppsIfReady();
@@ -318,7 +336,7 @@ bool InstallablePaymentAppCrawler::CompleteAndStorePaymentWebAppInfoIfValid(
return true;
}
-void InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
+bool InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
const GURL& method_manifest_url,
const GURL& web_app_manifest_url,
std::unique_ptr<std::vector<PaymentManifestParser::WebAppIcon>> icons) {
@@ -328,7 +346,7 @@ void InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
"web app manifest \"" +
web_app_manifest_url.spec() + "\" for payment handler manifest \"" +
method_manifest_url.spec() + "\".");
- return;
+ return false;
}
std::vector<blink::Manifest::ImageResource> manifest_icons;
@@ -371,7 +389,7 @@ void InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
web_app_manifest_url.spec() +
"\" for payment handler manifest \"" +
method_manifest_url.spec() + "\".");
- return;
+ return false;
}
// Stop if the web_contents is gone.
@@ -381,7 +399,7 @@ void InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
"manifest \"" +
web_app_manifest_url.spec() + "\" for payment handler manifest \"" +
method_manifest_url.spec() + "\").");
- return;
+ return false;
}
gfx::NativeView native_view = web_contents()->GetNativeView();
@@ -395,10 +413,29 @@ void InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
web_app_manifest_url.spec() +
"\" for payment handler manifest \"" +
method_manifest_url.spec() + "\".");
- return;
+ return false;
}
number_of_web_app_icons_to_download_and_decode_++;
+
+ // If the initiator frame doesn't exists any more, e.g. the frame has
+ // navigated away, don't download the icon.
+ // TODO(crbug.com/1058840): Move this sanity check to ManifestIconDownloader
+ // after DownloadImage refactor is done.
+ content::RenderFrameHost* render_frame_host =
+ content::RenderFrameHost::FromID(initiator_frame_routing_id_);
+ if (!render_frame_host || !render_frame_host->IsCurrent() ||
+ content::WebContents::FromRenderFrameHost(render_frame_host) !=
+ web_contents()) {
+ // Post the result back asynchronously.
+ base::PostTask(
+ FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(
+ &InstallablePaymentAppCrawler::FinishCrawlingPaymentAppsIfReady,
+ weak_ptr_factory_.GetWeakPtr()));
+ return false;
+ }
+
bool can_download_icon = content::ManifestIconDownloader::Download(
web_contents(), downloader_->FindTestServerURL(best_icon_url),
IconSizeCalculator::IdealIconHeight(native_view),
@@ -407,8 +444,10 @@ void InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
&InstallablePaymentAppCrawler::OnPaymentWebAppIconDownloadAndDecoded,
weak_ptr_factory_.GetWeakPtr(), method_manifest_url,
web_app_manifest_url),
- false /* square_only */);
+ false, /* square_only */
+ initiator_frame_routing_id_);
DCHECK(can_download_icon);
+ return can_download_icon;
}
void InstallablePaymentAppCrawler::OnPaymentWebAppIconDownloadAndDecoded(
@@ -416,16 +455,19 @@ void InstallablePaymentAppCrawler::OnPaymentWebAppIconDownloadAndDecoded(
const GURL& web_app_manifest_url,
const SkBitmap& icon) {
number_of_web_app_icons_to_download_and_decode_--;
+ auto it = installable_apps_.find(method_manifest_url);
+ DCHECK(it != installable_apps_.end());
+ DCHECK(IsSameOriginWith(GURL(it->second->sw_scope), web_app_manifest_url));
if (icon.drawsNothing()) {
log_.Error(
"Failed to download or decode the icon from web app manifest \"" +
web_app_manifest_url.spec() + "\" for payment handler manifest \"" +
method_manifest_url.spec() + "\".");
+ std::string error_message = base::ReplaceStringPlaceholders(
+ errors::kInvalidWebAppIcon, {web_app_manifest_url.spec()}, nullptr);
+ SetFirstError(error_message);
+ installable_apps_.erase(it);
} else {
- auto it = installable_apps_.find(method_manifest_url);
- DCHECK(it != installable_apps_.end());
- DCHECK(IsSameOriginWith(GURL(it->second->sw_scope), web_app_manifest_url));
-
it->second->icon = std::make_unique<SkBitmap>(icon);
}
diff --git a/chromium/components/payments/content/installable_payment_app_crawler.h b/chromium/components/payments/content/installable_payment_app_crawler.h
index 6e9d7447f33..00fc072767a 100644
--- a/chromium/components/payments/content/installable_payment_app_crawler.h
+++ b/chromium/components/payments/content/installable_payment_app_crawler.h
@@ -19,12 +19,15 @@
#include "components/payments/content/utility/payment_manifest_parser.h"
#include "components/payments/content/web_app_manifest.h"
#include "components/payments/core/payment_manifest_downloader.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
+#include "url/origin.h"
class GURL;
namespace content {
+class RenderFrameHost;
class WebContents;
}
@@ -39,13 +42,21 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver {
std::map<GURL, std::unique_ptr<WebAppInstallationInfo>>,
const std::string& error_message)>;
+ // |merchant_origin| is the origin of the iframe that created the
+ // PaymentRequest object. It is used by security features like
+ // 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'.
+ // |initiator_render_frame_host| is the iframe for |merchant_origin|.
+ //
// The owner of InstallablePaymentAppCrawler owns |downloader|, |parser| and
// |cache|. They should live until |finished_using_resources| parameter to
// Start() method is called.
- InstallablePaymentAppCrawler(content::WebContents* web_contents,
- PaymentManifestDownloader* downloader,
- PaymentManifestParser* parser,
- PaymentManifestWebDataService* cache);
+ InstallablePaymentAppCrawler(
+ const url::Origin& merchant_origin,
+ content::RenderFrameHost* initiator_render_frame_host,
+ content::WebContents* web_contents,
+ PaymentManifestDownloader* downloader,
+ PaymentManifestParser* parser,
+ PaymentManifestWebDataService* cache);
~InstallablePaymentAppCrawler() override;
// Starts the crawling process. All the url based payment methods in
@@ -89,7 +100,9 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver {
const GURL& method_manifest_url,
const GURL& web_app_manifest_url,
std::unique_ptr<WebAppInstallationInfo> app_info);
- void DownloadAndDecodeWebAppIcon(
+ // Returns true if an icon can get downloaded for the web app with the given
+ // manifest.
+ bool DownloadAndDecodeWebAppIcon(
const GURL& method_manifest_url,
const GURL& web_app_manifest_url,
std::unique_ptr<std::vector<PaymentManifestParser::WebAppIcon>> icons);
@@ -100,6 +113,8 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver {
void SetFirstError(const std::string& error_message);
DeveloperConsoleLogger log_;
+ const url::Origin merchant_origin_;
+ const content::GlobalFrameRoutingId initiator_frame_routing_id_;
PaymentManifestDownloader* downloader_;
PaymentManifestParser* parser_;
FinishedCrawlingCallback callback_;
diff --git a/chromium/components/payments/content/manifest_verifier.cc b/chromium/components/payments/content/manifest_verifier.cc
index 3549be8b719..0a7fb9b4ae4 100644
--- a/chromium/components/payments/content/manifest_verifier.cc
+++ b/chromium/components/payments/content/manifest_verifier.cc
@@ -58,11 +58,13 @@ void EnableMethodManifestUrlForSupportedApps(
} // namespace
-ManifestVerifier::ManifestVerifier(content::WebContents* web_contents,
+ManifestVerifier::ManifestVerifier(const url::Origin& merchant_origin,
+ content::WebContents* web_contents,
PaymentManifestDownloader* downloader,
PaymentManifestParser* parser,
PaymentManifestWebDataService* cache)
- : log_(web_contents),
+ : merchant_origin_(merchant_origin),
+ log_(web_contents),
downloader_(downloader),
parser_(parser),
cache_(cache),
@@ -203,7 +205,7 @@ void ManifestVerifier::OnWebDataServiceRequestDone(
}
downloader_->DownloadPaymentMethodManifest(
- method_manifest_url,
+ merchant_origin_, method_manifest_url,
base::BindOnce(&ManifestVerifier::OnPaymentMethodManifestDownloaded,
weak_ptr_factory_.GetWeakPtr(), method_manifest_url));
}
@@ -233,7 +235,7 @@ void ManifestVerifier::OnPaymentMethodManifestDownloaded(
}
parser_->ParsePaymentMethodManifest(
- content,
+ method_manifest_url, content,
base::BindOnce(&ManifestVerifier::OnPaymentMethodManifestParsed,
weak_ptr_factory_.GetWeakPtr(), method_manifest_url));
}
diff --git a/chromium/components/payments/content/manifest_verifier.h b/chromium/components/payments/content/manifest_verifier.h
index 80e608a77e4..3d05c7cf056 100644
--- a/chromium/components/payments/content/manifest_verifier.h
+++ b/chromium/components/payments/content/manifest_verifier.h
@@ -20,6 +20,7 @@
#include "components/webdata/common/web_data_service_consumer.h"
#include "content/public/browser/payment_app_provider.h"
#include "content/public/browser/web_contents_observer.h"
+#include "url/origin.h"
class GURL;
@@ -62,10 +63,16 @@ class ManifestVerifier final : public WebDataServiceConsumer {
const std::string& error_message)>;
// Creates the verifier and starts up the parser utility process.
+ //
+ // |merchant_origin| should be the origin of the iframe that created the
+ // PaymentRequest object. It is used by security features like
+ // 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'.
+ //
// The owner of ManifestVerifier owns |downloader|, |parser| and
// |cache|. They should live until |finished_using_resources| parameter to
// Verify() method is called.
- ManifestVerifier(content::WebContents* web_contents,
+ ManifestVerifier(const url::Origin& merchant_origin,
+ content::WebContents* web_contents,
PaymentManifestDownloader* downloader,
PaymentManifestParser* parser,
PaymentManifestWebDataService* cache);
@@ -102,6 +109,7 @@ class ManifestVerifier final : public WebDataServiceConsumer {
// Called immediately preceding the verification callback invocation.
void RemoveInvalidPaymentApps();
+ const url::Origin merchant_origin_;
DeveloperConsoleLogger log_;
// Downloads the manifests.
diff --git a/chromium/components/payments/content/payment_app_factory.h b/chromium/components/payments/content/payment_app_factory.h
index 28f03466b20..7d74c3a79a3 100644
--- a/chromium/components/payments/content/payment_app_factory.h
+++ b/chromium/components/payments/content/payment_app_factory.h
@@ -11,7 +11,9 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "components/payments/content/service_worker_payment_app_finder.h"
#include "components/payments/core/payment_app.h"
+#include "content/public/browser/payment_app_provider.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
class GURL;
@@ -21,6 +23,7 @@ class AutofillProfile;
} // namespace autofill
namespace content {
+class RenderFrameHost;
class WebContents;
} // namespace content
@@ -30,8 +33,9 @@ class Origin;
namespace payments {
-class PaymentRequestSpec;
class ContentPaymentRequestDelegate;
+class PaymentManifestWebDataService;
+class PaymentRequestSpec;
// Base class for a factory that can create instances of payment apps.
class PaymentAppFactory {
@@ -41,14 +45,23 @@ class PaymentAppFactory {
virtual ~Delegate() = default;
virtual content::WebContents* GetWebContents() = 0;
- virtual ContentPaymentRequestDelegate* GetPaymentRequestDelegate() = 0;
- virtual PaymentRequestSpec* GetSpec() = 0;
virtual const GURL& GetTopOrigin() = 0;
virtual const GURL& GetFrameOrigin() = 0;
+ virtual const url::Origin& GetFrameSecurityOrigin() = 0;
+ virtual content::RenderFrameHost* GetInitiatorRenderFrameHost() const = 0;
+ virtual const std::vector<mojom::PaymentMethodDataPtr>& GetMethodData()
+ const = 0;
+ virtual scoped_refptr<PaymentManifestWebDataService>
+ GetPaymentManifestWebDataService() const = 0;
+ virtual bool MayCrawlForInstallablePaymentApps() = 0;
+
+ // These parameters are only used to create native payment apps.
virtual const std::vector<autofill::AutofillProfile*>&
GetBillingProfiles() = 0;
virtual bool IsRequestedAutofillDataAvailable() = 0;
- virtual bool MayCrawlForInstallablePaymentApps() = 0;
+ virtual ContentPaymentRequestDelegate* GetPaymentRequestDelegate()
+ const = 0;
+ virtual PaymentRequestSpec* GetSpec() const = 0;
// Called after an app is installed. Used for just-in-time installable
// payment handlers, for example.
@@ -63,6 +76,18 @@ class PaymentAppFactory {
virtual void OnPaymentAppCreationError(
const std::string& error_message) = 0;
+ // Whether the factory should early exit before creating platform-specific
+ // PaymentApp objects. This is used by PaymentAppServiceBridge to skip
+ // creating native PaymentApps, which currently cannot be used over JNI.
+ virtual bool SkipCreatingNativePaymentApps() const = 0;
+
+ // When SkipCreatingNativePaymentApps() is true, this callback is called
+ // when service-worker payment app info is available.
+ virtual void OnCreatingNativePaymentAppsSkipped(
+ const content::PaymentAppProvider::PaymentApps& apps,
+ const ServiceWorkerPaymentAppFinder::InstallablePaymentApps&
+ installable_apps) = 0;
+
// Called when all apps of this factory have been created.
virtual void OnDoneCreatingPaymentApps() = 0;
};
diff --git a/chromium/components/payments/content/payment_app_service.cc b/chromium/components/payments/content/payment_app_service.cc
index 224077573ef..b0631dd395b 100644
--- a/chromium/components/payments/content/payment_app_service.cc
+++ b/chromium/components/payments/content/payment_app_service.cc
@@ -21,10 +21,12 @@ PaymentAppService::PaymentAppService() {
PaymentAppService::~PaymentAppService() = default;
+size_t PaymentAppService::GetNumberOfFactories() const {
+ return factories_.size();
+}
+
void PaymentAppService::Create(
- base::WeakPtr<PaymentAppFactory::Delegate> delegate,
- size_t* number_of_payment_app_factories) {
- *number_of_payment_app_factories = factories_.size();
+ base::WeakPtr<PaymentAppFactory::Delegate> delegate) {
for (const auto& factory : factories_) {
factory->Create(delegate);
}
diff --git a/chromium/components/payments/content/payment_app_service.h b/chromium/components/payments/content/payment_app_service.h
index 2a62d3f0745..cea8f09d206 100644
--- a/chromium/components/payments/content/payment_app_service.h
+++ b/chromium/components/payments/content/payment_app_service.h
@@ -22,14 +22,13 @@ class PaymentAppService : public KeyedService {
PaymentAppService();
~PaymentAppService() override;
- // Sets |number_of_payment_app_factories| to the number of payment app
- // factories, which is the number of times that
- // |delegate->OnDoneCreatingPaymentApps()| will be called. The value is passed
- // in as out-param instead of being returned, so it can be set before any
- // factory can call OnDoneCreatingPaymentApps(), which can happen for
- // factories that execute synchronously, e.g., AutofillPaymentAppFactory.
- void Create(base::WeakPtr<PaymentAppFactory::Delegate> delegate,
- size_t* number_of_payment_app_factories);
+ // Returns the number of payment app factories, which is the number of times
+ // that |delegate->OnDoneCreatingPaymentApps()| will be called as a result of
+ // Create().
+ size_t GetNumberOfFactories() const;
+
+ // Create payment apps for |delegate|.
+ void Create(base::WeakPtr<PaymentAppFactory::Delegate> delegate);
private:
std::vector<std::unique_ptr<PaymentAppFactory>> factories_;
diff --git a/chromium/components/payments/content/payment_app_unittest.cc b/chromium/components/payments/content/payment_app_unittest.cc
index 2edd15570d7..5d982a6f4ff 100644
--- a/chromium/components/payments/content/payment_app_unittest.cc
+++ b/chromium/components/payments/content/payment_app_unittest.cc
@@ -7,15 +7,20 @@
#include <vector>
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/payments/content/service_worker_payment_app.h"
#include "components/payments/core/autofill_payment_app.h"
+#include "components/payments/core/features.h"
#include "components/payments/core/mock_payment_request_delegate.h"
#include "content/public/browser/stored_payment_app.h"
+#include "content/public/browser/supported_delegations.h"
+#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_web_contents_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
@@ -48,6 +53,8 @@ class PaymentAppTest : public testing::TestWithParam<RequiredPaymentOptions>,
required_options_(GetParam()) {
local_card_.set_billing_address_id(address_.guid());
CreateSpec();
+ web_contents_ =
+ test_web_contents_factory_.CreateWebContents(&browser_context_);
}
std::unique_ptr<ServiceWorkerPaymentApp> CreateServiceWorkerPaymentApp(
@@ -56,8 +63,6 @@ class PaymentAppTest : public testing::TestWithParam<RequiredPaymentOptions>,
bool handles_name,
bool handles_phone,
bool handles_email) {
- constexpr int kBitmapDimension = 16;
-
std::unique_ptr<content::StoredPaymentApp> stored_app =
std::make_unique<content::StoredPaymentApp>();
stored_app->registration_id = 123456;
@@ -65,8 +70,7 @@ class PaymentAppTest : public testing::TestWithParam<RequiredPaymentOptions>,
stored_app->name = "bobpay";
stored_app->icon = std::make_unique<SkBitmap>();
if (can_preselect) {
- stored_app->icon->allocN32Pixels(kBitmapDimension, kBitmapDimension);
- stored_app->icon->eraseColor(SK_ColorRED);
+ PopulateIcon(stored_app->icon.get());
}
if (handles_shipping) {
stored_app->supported_delegations.shipping_address = true;
@@ -86,8 +90,45 @@ class PaymentAppTest : public testing::TestWithParam<RequiredPaymentOptions>,
GURL("https://testmerchant.com/bobpay"), spec_.get(),
std::move(stored_app), &delegate_,
/*identity_callback=*/
- base::Bind([](const url::Origin&,
- int64_t) { /* Intentionally left blank. */ }));
+ base::BindRepeating([](const url::Origin&,
+ int64_t) { /* Intentionally left blank. */ }));
+ }
+
+ std::unique_ptr<ServiceWorkerPaymentApp>
+ CreateInstallableServiceWorkerPaymentApp(bool can_preselect,
+ bool handles_shipping,
+ bool handles_name,
+ bool handles_phone,
+ bool handles_email) {
+ auto installable_app = std::make_unique<WebAppInstallationInfo>();
+ installable_app->name = "installable_pay";
+ installable_app->sw_js_url = "https://pay.example/app.js";
+ installable_app->sw_scope = "https://pay.example";
+ installable_app->icon = std::make_unique<SkBitmap>();
+ if (can_preselect)
+ PopulateIcon(installable_app->icon.get());
+ if (handles_shipping)
+ installable_app->supported_delegations.shipping_address = true;
+ if (handles_name)
+ installable_app->supported_delegations.payer_name = true;
+ if (handles_phone)
+ installable_app->supported_delegations.payer_phone = true;
+ if (handles_email)
+ installable_app->supported_delegations.payer_email = true;
+
+ return std::make_unique<ServiceWorkerPaymentApp>(
+ web_contents_, GURL("https://merchant.example"),
+ GURL("https://merchant.example/iframe"), spec_.get(),
+ std::move(installable_app), "https://pay.example", &delegate_,
+ /*identity_callback=*/
+ base::BindRepeating([](const url::Origin&,
+ int64_t) { /* Intentionally left blank. */ }));
+ }
+
+ static void PopulateIcon(SkBitmap* icon) {
+ constexpr int kBitmapDimension = 16;
+ icon->allocN32Pixels(kBitmapDimension, kBitmapDimension);
+ icon->eraseColor(SK_ColorRED);
}
autofill::CreditCard& local_credit_card() { return local_card_; }
@@ -132,6 +173,8 @@ class PaymentAppTest : public testing::TestWithParam<RequiredPaymentOptions>,
content::BrowserTaskEnvironment task_environment_;
content::TestBrowserContext browser_context_;
+ content::TestWebContentsFactory test_web_contents_factory_;
+ content::WebContents* web_contents_;
autofill::AutofillProfile address_;
autofill::CreditCard local_card_;
std::vector<autofill::AutofillProfile*> billing_profiles_;
@@ -154,27 +197,17 @@ INSTANTIATE_TEST_SUITE_P(
TEST_P(PaymentAppTest, SortApps) {
std::vector<PaymentApp*> apps;
- // Add a complete app with mismatching type.
- autofill::CreditCard complete_dismatching_card = local_credit_card();
- AutofillPaymentApp complete_dismatching_cc_app(
- "visa", complete_dismatching_card,
- /*matches_merchant_card_type_exactly=*/false, billing_profiles(), "en-US",
- nullptr);
- apps.push_back(&complete_dismatching_cc_app);
-
- // Add an app with no billing address.
+ // Add a card with no billing address.
autofill::CreditCard card_with_no_address = local_credit_card();
card_with_no_address.set_billing_address_id("");
AutofillPaymentApp cc_app_with_no_address(
- "visa", card_with_no_address, /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ "visa", card_with_no_address, billing_profiles(), "en-US", nullptr);
apps.push_back(&cc_app_with_no_address);
- // Add an expired app.
+ // Add an expired card.
autofill::CreditCard expired_card = local_credit_card();
expired_card.SetExpirationYear(2016);
AutofillPaymentApp expired_cc_app("visa", expired_card,
- /*matches_merchant_card_type_exactly=*/true,
billing_profiles(), "en-US", nullptr);
apps.push_back(&expired_cc_app);
@@ -194,40 +227,35 @@ TEST_P(PaymentAppTest, SortApps) {
false /* = handles_email */);
apps.push_back(preselectable_sw_app.get());
- // Add an app with no name.
+ // Add a card with no name.
autofill::CreditCard card_with_no_name = local_credit_card();
card_with_no_name.SetInfo(
autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
base::ASCIIToUTF16(""), "en-US");
- AutofillPaymentApp cc_app_with_no_name(
- "visa", card_with_no_name, /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp cc_app_with_no_name("visa", card_with_no_name,
+ billing_profiles(), "en-US", nullptr);
apps.push_back(&cc_app_with_no_name);
- // Add a complete matching app.
- autofill::CreditCard complete_matching_card = local_credit_card();
- AutofillPaymentApp complete_matching_cc_app(
- "visa", complete_matching_card,
- /*matches_merchant_card_type_exactly=*/true, billing_profiles(), "en-US",
- nullptr);
- apps.push_back(&complete_matching_cc_app);
+ // Add a complete card.
+ autofill::CreditCard complete_card = local_credit_card();
+ AutofillPaymentApp complete_cc_app("visa", complete_card, billing_profiles(),
+ "en-US", nullptr);
+ apps.push_back(&complete_cc_app);
- // Add an app with no number.
+ // Add a card with no number.
autofill::CreditCard card_with_no_number = local_credit_card();
card_with_no_number.SetNumber(base::ASCIIToUTF16(""));
AutofillPaymentApp cc_app_with_no_number(
- "visa", card_with_no_number, /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ "visa", card_with_no_number, billing_profiles(), "en-US", nullptr);
apps.push_back(&cc_app_with_no_number);
- // Add a complete matching app that is most frequently used.
+ // Add a complete matching card that is most frequently used.
autofill::CreditCard complete_frequently_used_card = local_credit_card();
AutofillPaymentApp complete_frequently_used_cc_app(
- "visa", complete_frequently_used_card,
- /*matches_merchant_card_type_exactly=*/true, billing_profiles(), "en-US",
+ "visa", complete_frequently_used_card, billing_profiles(), "en-US",
nullptr);
apps.push_back(&complete_frequently_used_cc_app);
- // Record use of this app.
+ // Record use of this card.
complete_frequently_used_cc_app.credit_card()->RecordAndLogUse();
// Sort the apps and validate the new order.
@@ -238,8 +266,7 @@ TEST_P(PaymentAppTest, SortApps) {
// Autfill apps (credit cards) come after sw apps.
EXPECT_EQ(apps[i++], &complete_frequently_used_cc_app);
- EXPECT_EQ(apps[i++], &complete_matching_cc_app);
- EXPECT_EQ(apps[i++], &complete_dismatching_cc_app);
+ EXPECT_EQ(apps[i++], &complete_cc_app);
EXPECT_EQ(apps[i++], &expired_cc_app);
EXPECT_EQ(apps[i++], &cc_app_with_no_name);
EXPECT_EQ(apps[i++], &cc_app_with_no_address);
@@ -347,4 +374,98 @@ TEST_P(PaymentAppTest, SortAppsBasedOnSupportedDelegations) {
}
}
+TEST_P(PaymentAppTest, SortApps_DownRankJustInTimePaymentApp) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(features::kDownRankJustInTimePaymentApp);
+
+ std::vector<PaymentApp*> apps;
+
+ // Add a card with no billing address.
+ autofill::CreditCard card_with_no_address = local_credit_card();
+ card_with_no_address.set_billing_address_id("");
+ AutofillPaymentApp cc_app_with_no_address(
+ "visa", card_with_no_address, billing_profiles(), "en-US", nullptr);
+ apps.push_back(&cc_app_with_no_address);
+
+ // Add an expired card.
+ autofill::CreditCard expired_card = local_credit_card();
+ expired_card.SetExpirationYear(2016);
+ AutofillPaymentApp expired_cc_app("visa", expired_card, billing_profiles(),
+ "en-US", nullptr);
+ apps.push_back(&expired_cc_app);
+
+ // Add a card with no number.
+ autofill::CreditCard card_with_no_number = local_credit_card();
+ card_with_no_number.SetNumber(base::ASCIIToUTF16(""));
+ AutofillPaymentApp cc_app_with_no_number(
+ "visa", card_with_no_number, billing_profiles(), "en-US", nullptr);
+ apps.push_back(&cc_app_with_no_number);
+
+ // Add a card with no name.
+ autofill::CreditCard card_with_no_name = local_credit_card();
+ card_with_no_name.SetInfo(
+ autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
+ base::ASCIIToUTF16(""), "en-US");
+ AutofillPaymentApp cc_app_with_no_name("visa", card_with_no_name,
+ billing_profiles(), "en-US", nullptr);
+ apps.push_back(&cc_app_with_no_name);
+
+ // Add a just-in-time installable sw based payment app.
+ std::unique_ptr<ServiceWorkerPaymentApp> installable_sw_app =
+ CreateInstallableServiceWorkerPaymentApp(
+ true /* = can_preselect */, false /* = handles_shipping */,
+ false /* = handles_name */, false /* = handles_phone */,
+ false /* = handles_email */);
+ apps.push_back(installable_sw_app.get());
+
+ // Add an installed, non-preselectable sw based payment app.
+ std::unique_ptr<ServiceWorkerPaymentApp> non_preselectable_sw_app =
+ CreateServiceWorkerPaymentApp(
+ false /* = can_preselect */, false /* = handles_shipping */,
+ false /* = handles_name */, false /* = handles_phone */,
+ false /* = handles_email */);
+ apps.push_back(non_preselectable_sw_app.get());
+
+ // Add an installed, preselectable, sw based payment app.
+ std::unique_ptr<ServiceWorkerPaymentApp> preselectable_sw_app =
+ CreateServiceWorkerPaymentApp(
+ true /* = can_preselect */, false /* = handles_shipping */,
+ false /* = handles_name */, false /* = handles_phone */,
+ false /* = handles_email */);
+ apps.push_back(preselectable_sw_app.get());
+
+ // Add a complete card.
+ autofill::CreditCard complete_card = local_credit_card();
+ AutofillPaymentApp complete_cc_app("visa", complete_card, billing_profiles(),
+ "en-US", nullptr);
+ apps.push_back(&complete_cc_app);
+
+ // Add a complete matching card that is most frequently used.
+ autofill::CreditCard complete_frequently_used_card = local_credit_card();
+ AutofillPaymentApp complete_frequently_used_cc_app(
+ "visa", complete_frequently_used_card, billing_profiles(), "en-US",
+ nullptr);
+ apps.push_back(&complete_frequently_used_cc_app);
+ // Record use of this card.
+ complete_frequently_used_cc_app.credit_card()->RecordAndLogUse();
+
+ // Sort the apps and validate the new order.
+ PaymentApp::SortApps(&apps);
+ size_t i = 0;
+
+ // Installed sw based payment handlers come first.
+ EXPECT_EQ(apps[i++], preselectable_sw_app.get());
+ EXPECT_EQ(apps[i++], non_preselectable_sw_app.get());
+ // Complete autofill apps are sorted by frecency.
+ EXPECT_EQ(apps[i++], &complete_frequently_used_cc_app);
+ EXPECT_EQ(apps[i++], &complete_cc_app);
+ EXPECT_EQ(apps[i++], &expired_cc_app);
+ // Just-in-time installable sw based payment apps come after autofill apps.
+ EXPECT_EQ(apps[i++], installable_sw_app.get());
+ // Incomplete autofill apps (credit cards) come last.
+ EXPECT_EQ(apps[i++], &cc_app_with_no_name);
+ EXPECT_EQ(apps[i++], &cc_app_with_no_address);
+ EXPECT_EQ(apps[i++], &cc_app_with_no_number);
+}
+
} // namespace payments
diff --git a/chromium/components/payments/content/payment_event_response_util.cc b/chromium/components/payments/content/payment_event_response_util.cc
index 3742ae3d946..4ace52f9ba1 100644
--- a/chromium/components/payments/content/payment_event_response_util.cc
+++ b/chromium/components/payments/content/payment_event_response_util.cc
@@ -10,6 +10,45 @@
namespace payments {
+base::StringPiece ConvertCanMakePaymentEventResponseTypeToErrorString(
+ mojom::CanMakePaymentEventResponseType response_type) {
+ switch (response_type) {
+ case mojom::CanMakePaymentEventResponseType::BOOLEAN_CONVERSION_ERROR:
+ return errors::kCanMakePaymentEventBooleanConversionError;
+ case mojom::CanMakePaymentEventResponseType::BROWSER_ERROR:
+ return errors::kCanMakePaymentEventBrowserError;
+ case mojom::CanMakePaymentEventResponseType::INTERNAL_ERROR:
+ return errors::kCanMakePaymentEventInternalError;
+ case mojom::CanMakePaymentEventResponseType::INVALID_ACCOUNT_BALANCE_VALUE:
+ return errors::kCanMakePaymentEventInvalidAccountBalanceValue;
+ case mojom::CanMakePaymentEventResponseType::
+ MINIMAL_UI_RESPONSE_CONVERSION_ERROR:
+ return errors::kCanMakePaymentEventMinimalUiResponseConversionError;
+ case mojom::CanMakePaymentEventResponseType::NO_ACCOUNT_BALANCE_VALUE:
+ return errors::kCanMakePaymentEventNoAccountBalanceValue;
+ case mojom::CanMakePaymentEventResponseType::NO_CAN_MAKE_PAYMENT_VALUE:
+ return errors::kCanMakePaymentEventNoCanMakePaymentValue;
+ case mojom::CanMakePaymentEventResponseType::NO_EXPLICITLY_VERIFIED_METHODS:
+ return errors::kCanMakePaymentEventNoExplicitlyVerifiedMethods;
+ case mojom::CanMakePaymentEventResponseType::NO_READY_FOR_MINIMAL_UI_VALUE:
+ return errors::kCanMakePaymentEventNoReadyForMinimalUiValue;
+ case mojom::CanMakePaymentEventResponseType::NO_RESPONSE:
+ return errors::kCanMakePaymentEventNoResponse;
+ case mojom::CanMakePaymentEventResponseType::NOT_INSTALLED:
+ return errors::kCanMakePaymentEventNotInstalled;
+ case mojom::CanMakePaymentEventResponseType::NO_URL_BASED_PAYMENT_METHODS:
+ return errors::kCanMakePaymentEventNoUrlBasedPaymentMethods;
+ case mojom::CanMakePaymentEventResponseType::REJECT:
+ return errors::kCanMakePaymentEventRejected;
+ case mojom::CanMakePaymentEventResponseType::TIMEOUT:
+ return errors::kCanMakePaymentEventTimeout;
+ case mojom::CanMakePaymentEventResponseType::INCOGNITO:
+ // Intentionally fallthrough.
+ case mojom::CanMakePaymentEventResponseType::SUCCESS:
+ return "";
+ }
+}
+
base::StringPiece ConvertPaymentEventResponseTypeToErrorString(
mojom::PaymentEventResponseType response_type) {
switch (response_type) {
diff --git a/chromium/components/payments/content/payment_event_response_util.h b/chromium/components/payments/content/payment_event_response_util.h
index afa0c53dfc5..7ec6a20e2a0 100644
--- a/chromium/components/payments/content/payment_event_response_util.h
+++ b/chromium/components/payments/content/payment_event_response_util.h
@@ -10,6 +10,11 @@
namespace payments {
+// Converts the given 'canmakepayment' event |response_type| into a
+// developer-facing error string. SUCCESS is converted into an empty string.
+base::StringPiece ConvertCanMakePaymentEventResponseTypeToErrorString(
+ mojom::CanMakePaymentEventResponseType response_type);
+
// Converts the given 'paymentrequest' event |response_type| into a
// developer-facing error string. PAYMENT_EVENT_SUCCESS is converted into an
// empty string.
diff --git a/chromium/components/payments/content/payment_manifest_web_data_service.cc b/chromium/components/payments/content/payment_manifest_web_data_service.cc
index 1cd0d2d02ed..8294b9eaac2 100644
--- a/chromium/components/payments/content/payment_manifest_web_data_service.cc
+++ b/chromium/components/payments/content/payment_manifest_web_data_service.cc
@@ -15,9 +15,8 @@ namespace payments {
PaymentManifestWebDataService::PaymentManifestWebDataService(
scoped_refptr<WebDatabaseService> wdbs,
- const ProfileErrorCallback& callback,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
- : WebDataServiceBase(wdbs, callback, ui_task_runner) {}
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+ : WebDataServiceBase(std::move(wdbs), std::move(ui_task_runner)) {}
PaymentManifestWebDataService::~PaymentManifestWebDataService() {}
@@ -25,8 +24,9 @@ void PaymentManifestWebDataService::AddPaymentWebAppManifest(
std::vector<WebAppManifestSection> manifest) {
wdbs_->ScheduleDBTask(
FROM_HERE,
- base::Bind(&PaymentManifestWebDataService::AddPaymentWebAppManifestImpl,
- this, std::move(manifest)));
+ base::BindOnce(
+ &PaymentManifestWebDataService::AddPaymentWebAppManifestImpl, this,
+ std::move(manifest)));
}
WebDatabase::State PaymentManifestWebDataService::AddPaymentWebAppManifestImpl(
@@ -45,8 +45,9 @@ void PaymentManifestWebDataService::AddPaymentMethodManifest(
std::vector<std::string> app_package_names) {
wdbs_->ScheduleDBTask(
FROM_HERE,
- base::Bind(&PaymentManifestWebDataService::AddPaymentMethodManifestImpl,
- this, payment_method, std::move(app_package_names)));
+ base::BindOnce(
+ &PaymentManifestWebDataService::AddPaymentMethodManifestImpl, this,
+ payment_method, std::move(app_package_names)));
}
WebDatabase::State PaymentManifestWebDataService::AddPaymentMethodManifestImpl(
@@ -67,8 +68,9 @@ PaymentManifestWebDataService::GetPaymentWebAppManifest(
WebDataServiceConsumer* consumer) {
return wdbs_->ScheduleDBTaskWithResult(
FROM_HERE,
- base::Bind(&PaymentManifestWebDataService::GetPaymentWebAppManifestImpl,
- this, web_app),
+ base::BindOnce(
+ &PaymentManifestWebDataService::GetPaymentWebAppManifestImpl, this,
+ web_app),
consumer);
}
@@ -89,8 +91,9 @@ PaymentManifestWebDataService::GetPaymentMethodManifest(
WebDataServiceConsumer* consumer) {
return wdbs_->ScheduleDBTaskWithResult(
FROM_HERE,
- base::Bind(&PaymentManifestWebDataService::GetPaymentMethodManifestImpl,
- this, payment_method),
+ base::BindOnce(
+ &PaymentManifestWebDataService::GetPaymentMethodManifestImpl, this,
+ payment_method),
consumer);
}
@@ -110,4 +113,4 @@ void PaymentManifestWebDataService::RemoveExpiredData(WebDatabase* db) {
WebAppManifestSectionTable::FromWebDatabase(db)->RemoveExpiredData();
}
-} // namespace payments \ No newline at end of file
+} // namespace payments
diff --git a/chromium/components/payments/content/payment_manifest_web_data_service.h b/chromium/components/payments/content/payment_manifest_web_data_service.h
index a57a7645b1e..e81845e9cb3 100644
--- a/chromium/components/payments/content/payment_manifest_web_data_service.h
+++ b/chromium/components/payments/content/payment_manifest_web_data_service.h
@@ -29,8 +29,7 @@ class PaymentManifestWebDataService : public WebDataServiceBase {
public:
PaymentManifestWebDataService(
scoped_refptr<WebDatabaseService> wdbs,
- const ProfileErrorCallback& callback,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
// Adds the web app |manifest|.
void AddPaymentWebAppManifest(std::vector<WebAppManifestSection> manifest);
diff --git a/chromium/components/payments/content/payment_request.cc b/chromium/components/payments/content/payment_request.cc
index d8eab2d1733..dd5ee3b26fd 100644
--- a/chromium/components/payments/content/payment_request.cc
+++ b/chromium/components/payments/content/payment_request.cc
@@ -18,6 +18,7 @@
#include "components/payments/content/payment_request_converter.h"
#include "components/payments/content/payment_request_web_contents_manager.h"
#include "components/payments/core/can_make_payment_query.h"
+#include "components/payments/core/error_message_util.h"
#include "components/payments/core/error_strings.h"
#include "components/payments/core/features.h"
#include "components/payments/core/method_strings.h"
@@ -34,9 +35,11 @@
#include "components/url_formatter/elide_url.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/common/origin_util.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
namespace payments {
namespace {
@@ -49,27 +52,6 @@ bool IsGooglePaymentMethod(const std::string& method_name) {
method_name == methods::kAndroidPay;
}
-std::string GetNotSupportedErrorMessage(PaymentRequestSpec* spec) {
- if (!spec || spec->payment_method_identifiers_set().empty())
- return errors::kGenericPaymentMethodNotSupportedMessage;
-
- std::vector<std::string> method_names(
- spec->payment_method_identifiers_set().size());
- std::transform(
- spec->payment_method_identifiers_set().begin(),
- spec->payment_method_identifiers_set().end(), method_names.begin(),
- [](const std::string& method_name) { return "\"" + method_name + "\""; });
-
- std::string output;
- bool replaced = base::ReplaceChars(
- method_names.size() == 1
- ? errors::kSinglePaymentMethodNotSupportedFormat
- : errors::kMultiplePaymentMethodsNotSupportedFormat,
- "$", base::JoinString(method_names, ", "), &output);
- DCHECK(replaced);
- return output;
-}
-
// Redact shipping address before exposing it in ShippingAddressChangeEvent.
// https://w3c.github.io/payment-request/#shipping-address-changed-algorithm
mojom::PaymentAddressPtr RedactShippingAddress(
@@ -97,6 +79,11 @@ PaymentRequest::PaymentRequest(
mojo::PendingReceiver<mojom::PaymentRequest> receiver,
ObserverForTest* observer_for_testing)
: web_contents_(web_contents),
+ // TODO(crbug.com/1058840): change to WeakPtr<RenderFrameHost> once
+ // RenderFrameHost provides a WeakPtr API.
+ initiator_frame_routing_id_(content::GlobalFrameRoutingId(
+ render_frame_host->GetProcess()->GetID(),
+ render_frame_host->GetRoutingID())),
log_(web_contents_),
delegate_(std::move(delegate)),
manager_(manager),
@@ -107,6 +94,7 @@ PaymentRequest::PaymentRequest(
web_contents_->GetLastCommittedURL())),
frame_origin_(url_formatter::FormatUrlForSecurityDisplay(
render_frame_host->GetLastCommittedURL())),
+ frame_security_origin_(render_frame_host->GetLastCommittedOrigin()),
observer_for_testing_(observer_for_testing),
journey_logger_(delegate_->IsIncognito(),
ukm::GetSourceIdForWebContentsDocument(web_contents)) {
@@ -181,11 +169,22 @@ void PaymentRequest::Init(
return;
}
+ // TODO(crbug.com/1058840): change to WeakPtr<RenderFrameHost> once
+ // RenderFrameHost provides a WeakPtr API.
+ content::RenderFrameHost* initiator_frame =
+ content::RenderFrameHost::FromID(initiator_frame_routing_id_);
+ if (!initiator_frame) {
+ log_.Error(errors::kInvalidInitiatorFrame);
+ OnConnectionTerminated();
+ return;
+ }
+
spec_ = std::make_unique<PaymentRequestSpec>(
std::move(options), std::move(details), std::move(method_data),
/*observer=*/this, delegate_->GetApplicationLocale());
state_ = std::make_unique<PaymentRequestState>(
- web_contents_, top_level_origin_, frame_origin_, spec_.get(),
+ web_contents_, initiator_frame, top_level_origin_, frame_origin_,
+ frame_security_origin_, spec_.get(),
/*delegate=*/this, delegate_->GetApplicationLocale(),
delegate_->GetPersonalDataManager(), delegate_.get(),
base::BindRepeating(&PaymentRequest::SetInvokedServiceWorkerIdentity,
@@ -422,6 +421,9 @@ void PaymentRequest::Abort() {
if (observer_for_testing_)
observer_for_testing_->OnAbortCalled();
+
+ if (accepting_abort)
+ state_->OnAbort();
}
void PaymentRequest::Complete(mojom::PaymentComplete result) {
@@ -574,7 +576,9 @@ void PaymentRequest::AreRequestedMethodsSupportedCallback(
journey_logger_.SetNotShown(
JourneyLogger::NOT_SHOWN_REASON_NO_SUPPORTED_PAYMENT_METHOD);
client_->OnError(mojom::PaymentErrorReason::NOT_SUPPORTED,
- GetNotSupportedErrorMessage(spec_.get()) +
+ GetNotSupportedErrorMessage(
+ spec_ ? spec_->payment_method_identifiers_set()
+ : std::set<std::string>()) +
(error_message.empty() ? "" : " " + error_message));
if (observer_for_testing_)
observer_for_testing_->OnNotSupportedError();
@@ -776,6 +780,14 @@ bool PaymentRequest::IsIncognito() const {
return delegate_->IsIncognito();
}
+void PaymentRequest::OnPaymentHandlerOpenWindowCalled() {
+ DCHECK(state_->selected_app());
+ // UKM for payment app origin should get recorded only when the origin of the
+ // invoked payment app is shown to the user.
+ journey_logger_.SetPaymentAppUkmSourceId(
+ state_->selected_app()->UkmSourceId());
+}
+
void PaymentRequest::RecordFirstAbortReason(
JourneyLogger::AbortReason abort_reason) {
if (!has_recorded_completion_) {
diff --git a/chromium/components/payments/content/payment_request.h b/chromium/components/payments/content/payment_request.h
index 5c77ab5d804..c7ca2024fa3 100644
--- a/chromium/components/payments/content/payment_request.h
+++ b/chromium/components/payments/content/payment_request.h
@@ -17,10 +17,12 @@
#include "components/payments/content/payment_request_state.h"
#include "components/payments/content/service_worker_payment_app.h"
#include "components/payments/core/journey_logger.h"
+#include "content/public/browser/global_routing_id.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
#include "url/gurl.h"
+#include "url/origin.h"
namespace content {
class RenderFrameHost;
@@ -125,6 +127,9 @@ class PaymentRequest : public mojom::PaymentRequest,
bool IsIncognito() const;
+ // Called when the payment handler requests to open a payment handler window.
+ void OnPaymentHandlerOpenWindowCalled();
+
content::WebContents* web_contents() { return web_contents_; }
bool skipped_payment_request_ui() { return skipped_payment_request_ui_; }
@@ -183,6 +188,7 @@ class PaymentRequest : public mojom::PaymentRequest,
bool warn_localhost_or_file);
content::WebContents* web_contents_;
+ const content::GlobalFrameRoutingId initiator_frame_routing_id_;
DeveloperConsoleLogger log_;
std::unique_ptr<ContentPaymentRequestDelegate> delegate_;
// |manager_| owns this PaymentRequest.
@@ -199,14 +205,22 @@ class PaymentRequest : public mojom::PaymentRequest,
// browser process.
PaymentHandlerHost payment_handler_host_;
- // The RFC 6454 origin of the top level frame that has invoked PaymentRequest
- // API. This is what the user sees in the address bar.
+ // The scheme, host, and port of the top level frame that has invoked
+ // PaymentRequest API as formatted by
+ // url_formatter::FormatUrlForSecurityDisplay(). This is what the user sees in
+ // the address bar.
const GURL top_level_origin_;
- // The RFC 6454 origin of the frame that has invoked PaymentRequest API. This
- // can be either the main frame or an iframe.
+ // The scheme, host, and port of the frame that has invoked PaymentRequest API
+ // as formatted by url_formatter::FormatUrlForSecurityDisplay(). This can be
+ // either the main frame or an iframe.
const GURL frame_origin_;
+ // The security origin of the frame that has invoked PaymentRequest API. This
+ // can be opaque. Used by security features like 'Sec-Fetch-Site' and
+ // 'Cross-Origin-Resource-Policy'.
+ const url::Origin frame_security_origin_;
+
// May be null, must outlive this object.
ObserverForTest* observer_for_testing_;
diff --git a/chromium/components/payments/content/payment_request_converter.cc b/chromium/components/payments/content/payment_request_converter.cc
index 8a1abc13c1f..d11a982dd5a 100644
--- a/chromium/components/payments/content/payment_request_converter.cc
+++ b/chromium/components/payments/content/payment_request_converter.cc
@@ -57,20 +57,6 @@ PaymentShippingOption ConvertPaymentShippingOption(
} // namespace
-autofill::CreditCard::CardType GetBasicCardType(
- const mojom::BasicCardType& type) {
- switch (type) {
- case mojom::BasicCardType::CREDIT:
- return autofill::CreditCard::CARD_TYPE_CREDIT;
- case mojom::BasicCardType::DEBIT:
- return autofill::CreditCard::CARD_TYPE_DEBIT;
- case mojom::BasicCardType::PREPAID:
- return autofill::CreditCard::CARD_TYPE_PREPAID;
- }
- NOTREACHED();
- return autofill::CreditCard::CARD_TYPE_UNKNOWN;
-}
-
std::string GetBasicCardNetworkName(const mojom::BasicCardNetwork& network) {
switch (network) {
case mojom::BasicCardNetwork::AMEX:
@@ -105,10 +91,6 @@ PaymentMethodData ConvertPaymentMethodData(
method_data_entry->supported_networks) {
method_data.supported_networks.push_back(GetBasicCardNetworkName(network));
}
- for (const mojom::BasicCardType& type : method_data_entry->supported_types) {
- autofill::CreditCard::CardType card_type = GetBasicCardType(type);
- method_data.supported_types.insert(card_type);
- }
return method_data;
}
diff --git a/chromium/components/payments/content/payment_request_converter.h b/chromium/components/payments/content/payment_request_converter.h
index 3ad65c96d46..c953e9e9670 100644
--- a/chromium/components/payments/content/payment_request_converter.h
+++ b/chromium/components/payments/content/payment_request_converter.h
@@ -15,10 +15,6 @@ namespace payments {
class PaymentDetails;
class PaymentMethodData;
-// Returns the card type associated with the given BasicCardType.
-autofill::CreditCard::CardType GetBasicCardType(
- const mojom::BasicCardType& type);
-
// Returns the card network name associated with a given BasicCardNetwork. Names
// are inspired by https://www.w3.org/Payments/card-network-ids.
std::string GetBasicCardNetworkName(const mojom::BasicCardNetwork& network);
diff --git a/chromium/components/payments/content/payment_request_spec.cc b/chromium/components/payments/content/payment_request_spec.cc
index 31fe5c1792a..357311240bd 100644
--- a/chromium/components/payments/content/payment_request_spec.cc
+++ b/chromium/components/payments/content/payment_request_spec.cc
@@ -31,7 +31,6 @@ void PopulateValidatedMethodData(
std::vector<std::string>* supported_card_networks,
std::set<std::string>* basic_card_specified_networks,
std::set<std::string>* supported_card_networks_set,
- std::set<autofill::CreditCard::CardType>* supported_card_types_set,
std::vector<GURL>* url_payment_method_identifiers,
std::set<std::string>* payment_method_identifiers_set,
std::map<std::string, std::set<std::string>>* stringified_method_data) {
@@ -41,9 +40,6 @@ void PopulateValidatedMethodData(
payment_method_identifiers_set);
supported_card_networks_set->insert(supported_card_networks->begin(),
supported_card_networks->end());
-
- data_util::ParseSupportedCardTypes(method_data_vector,
- supported_card_types_set);
}
void PopulateValidatedMethodData(
@@ -51,7 +47,6 @@ void PopulateValidatedMethodData(
std::vector<std::string>* supported_card_networks,
std::set<std::string>* basic_card_specified_networks,
std::set<std::string>* supported_card_networks_set,
- std::set<autofill::CreditCard::CardType>* supported_card_types_set,
std::vector<GURL>* url_payment_method_identifiers,
std::set<std::string>* payment_method_identifiers_set,
std::map<std::string, std::set<std::string>>* stringified_method_data) {
@@ -68,8 +63,8 @@ void PopulateValidatedMethodData(
PopulateValidatedMethodData(
method_data_vector, supported_card_networks,
basic_card_specified_networks, supported_card_networks_set,
- supported_card_types_set, url_payment_method_identifiers,
- payment_method_identifiers_set, stringified_method_data);
+ url_payment_method_identifiers, payment_method_identifiers_set,
+ stringified_method_data);
}
std::string ToString(bool value) {
@@ -101,9 +96,8 @@ PaymentRequestSpec::PaymentRequestSpec(
UpdateSelectedShippingOption(/*after_update=*/false);
PopulateValidatedMethodData(
method_data_, &supported_card_networks_, &basic_card_specified_networks_,
- &supported_card_networks_set_, &supported_card_types_set_,
- &url_payment_method_identifiers_, &payment_method_identifiers_set_,
- &stringified_method_data_);
+ &supported_card_networks_set_, &url_payment_method_identifiers_,
+ &payment_method_identifiers_set_, &stringified_method_data_);
query_for_quota_ = stringified_method_data_;
if (base::Contains(payment_method_identifiers_set_, methods::kBasicCard) &&
@@ -372,7 +366,6 @@ PaymentRequestSpec::GetApplicableModifier(PaymentApp* selected_app) const {
DCHECK(details_->modifiers);
for (const auto& modifier : *details_->modifiers) {
std::set<std::string> supported_card_networks_set;
- std::set<autofill::CreditCard::CardType> supported_types;
// The following 4 are unused but required by PopulateValidatedMethodData.
std::set<std::string> basic_card_specified_networks;
std::vector<std::string> supported_networks;
@@ -382,14 +375,13 @@ PaymentRequestSpec::GetApplicableModifier(PaymentApp* selected_app) const {
PopulateValidatedMethodData(
{ConvertPaymentMethodData(modifier->method_data)}, &supported_networks,
&basic_card_specified_networks, &supported_card_networks_set,
- &supported_types, &url_payment_method_identifiers,
- &payment_method_identifiers_set, &stringified_method_data);
+ &url_payment_method_identifiers, &payment_method_identifiers_set,
+ &stringified_method_data);
if (selected_app->IsValidForModifier(
modifier->method_data->supported_method,
!modifier->method_data->supported_networks.empty(),
- supported_card_networks_set,
- !modifier->method_data->supported_types.empty(), supported_types)) {
+ supported_card_networks_set)) {
return &modifier;
}
}
diff --git a/chromium/components/payments/content/payment_request_spec.h b/chromium/components/payments/content/payment_request_spec.h
index ea28e958006..87af537dadd 100644
--- a/chromium/components/payments/content/payment_request_spec.h
+++ b/chromium/components/payments/content/payment_request_spec.h
@@ -144,10 +144,6 @@ class PaymentRequestSpec : public PaymentOptionsProvider,
const {
return stringified_method_data_;
}
- const std::set<autofill::CreditCard::CardType>& supported_card_types_set()
- const {
- return supported_card_types_set_;
- }
const std::vector<GURL>& url_payment_method_identifiers() const {
return url_payment_method_identifiers_;
}
@@ -247,8 +243,6 @@ class PaymentRequestSpec : public PaymentOptionsProvider,
std::vector<std::string> supported_card_networks_;
std::set<std::string> supported_card_networks_set_;
- std::set<autofill::CreditCard::CardType> supported_card_types_set_;
-
// Only the set of basic-card specified networks. NOTE: callers should use
// |supported_card_networks_set_| to check merchant support.
std::set<std::string> basic_card_specified_networks_;
diff --git a/chromium/components/payments/content/payment_request_state.cc b/chromium/components/payments/content/payment_request_state.cc
index d961d5d17f4..b2ee9bb3e00 100644
--- a/chromium/components/payments/content/payment_request_state.cc
+++ b/chromium/components/payments/content/payment_request_state.cc
@@ -33,19 +33,12 @@
#include "components/payments/core/payment_app.h"
#include "components/payments/core/payment_request_data_util.h"
#include "components/payments/core/payments_experimental_features.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_features.h"
namespace payments {
namespace {
-// Checks whether any of the |apps| return true in IsValidForCanMakePayment().
-bool GetHasEnrolledInstrument(
- const std::vector<std::unique_ptr<PaymentApp>>& apps) {
- return std::any_of(apps.begin(), apps.end(), [](const auto& app) {
- return app->IsValidForCanMakePayment();
- });
-}
-
// Invokes the |callback| with |status|.
void CallStatusCallback(PaymentRequestState::StatusCallback callback,
bool status) {
@@ -64,8 +57,10 @@ void PostStatusCallback(PaymentRequestState::StatusCallback callback,
PaymentRequestState::PaymentRequestState(
content::WebContents* web_contents,
+ content::RenderFrameHost* initiator_render_frame_host,
const GURL& top_level_origin,
const GURL& frame_origin,
+ const url::Origin& frame_security_origin,
PaymentRequestSpec* spec,
Delegate* delegate,
const std::string& app_locale,
@@ -74,8 +69,10 @@ PaymentRequestState::PaymentRequestState(
const ServiceWorkerPaymentApp::IdentityCallback& sw_identity_callback,
JourneyLogger* journey_logger)
: web_contents_(web_contents),
+ initiator_render_frame_host_(initiator_render_frame_host),
top_origin_(top_level_origin),
frame_origin_(frame_origin),
+ frame_security_origin_(frame_security_origin),
app_locale_(app_locale),
spec_(spec),
delegate_(delegate),
@@ -89,10 +86,10 @@ PaymentRequestState::PaymentRequestState(
PopulateProfileCache();
// |web_contents_| is null in unit tests.
- PaymentAppServiceFactory::GetForContext(
- web_contents_ ? web_contents_->GetBrowserContext() : nullptr)
- ->Create(weak_ptr_factory_.GetWeakPtr(),
- &number_of_payment_app_factories_);
+ PaymentAppService* service = PaymentAppServiceFactory::GetForContext(
+ web_contents_ ? web_contents_->GetBrowserContext() : nullptr);
+ number_of_payment_app_factories_ = service->GetNumberOfFactories();
+ service->Create(weak_ptr_factory_.GetWeakPtr());
spec_->AddObserver(this);
}
@@ -103,12 +100,12 @@ content::WebContents* PaymentRequestState::GetWebContents() {
return web_contents_;
}
-ContentPaymentRequestDelegate*
-PaymentRequestState::GetPaymentRequestDelegate() {
+ContentPaymentRequestDelegate* PaymentRequestState::GetPaymentRequestDelegate()
+ const {
return payment_request_delegate_;
}
-PaymentRequestSpec* PaymentRequestState::GetSpec() {
+PaymentRequestSpec* PaymentRequestState::GetSpec() const {
return spec_;
}
@@ -120,6 +117,25 @@ const GURL& PaymentRequestState::GetFrameOrigin() {
return frame_origin_;
}
+const url::Origin& PaymentRequestState::GetFrameSecurityOrigin() {
+ return frame_security_origin_;
+}
+
+content::RenderFrameHost* PaymentRequestState::GetInitiatorRenderFrameHost()
+ const {
+ return initiator_render_frame_host_;
+}
+
+const std::vector<mojom::PaymentMethodDataPtr>&
+PaymentRequestState::GetMethodData() const {
+ return GetSpec()->method_data();
+}
+
+scoped_refptr<PaymentManifestWebDataService>
+PaymentRequestState::GetPaymentManifestWebDataService() const {
+ return GetPaymentRequestDelegate()->GetPaymentManifestWebDataService();
+}
+
const std::vector<autofill::AutofillProfile*>&
PaymentRequestState::GetBillingProfiles() {
return shipping_profiles_;
@@ -160,6 +176,17 @@ void PaymentRequestState::OnPaymentAppCreationError(
get_all_payment_apps_error_ = error_message;
}
+bool PaymentRequestState::SkipCreatingNativePaymentApps() const {
+ return false;
+}
+
+void PaymentRequestState::OnCreatingNativePaymentAppsSkipped(
+ const content::PaymentAppProvider::PaymentApps& unused_apps,
+ const ServiceWorkerPaymentAppFinder::InstallablePaymentApps&
+ unused_installable_apps) {
+ NOTREACHED();
+}
+
void PaymentRequestState::OnDoneCreatingPaymentApps() {
DCHECK_NE(0U, number_of_payment_app_factories_);
if (--number_of_payment_app_factories_ > 0U)
@@ -168,7 +195,9 @@ void PaymentRequestState::OnDoneCreatingPaymentApps() {
SetDefaultProfileSelections();
get_all_apps_finished_ = true;
- has_enrolled_instrument_ = GetHasEnrolledInstrument(available_apps_);
+ has_enrolled_instrument_ =
+ std::any_of(available_apps_.begin(), available_apps_.end(),
+ [](const auto& app) { return app->HasEnrolledInstrument(); });
are_requested_methods_supported_ |= !available_apps_.empty();
NotifyOnGetAllPaymentAppsFinished();
NotifyInitialized();
@@ -263,6 +292,13 @@ void PaymentRequestState::AreRequestedMethodsSupported(
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
+void PaymentRequestState::OnAbort() {
+ // Reset supported method callback when the merchant calls abort before
+ // OnDoneCreatingPaymentApps().
+ if (are_requested_methods_supported_callback_)
+ are_requested_methods_supported_callback_.Reset();
+}
+
void PaymentRequestState::CheckRequestedMethodsSupported(
MethodsSupportedCallback callback) {
DCHECK(get_all_apps_finished_);
@@ -598,6 +634,7 @@ void PaymentRequestState::SetDefaultProfileSelections() {
selected_app_ = nullptr;
if (!available_apps_.empty() && available_apps_[0]->CanPreselect()) {
selected_app_ = available_apps_[0].get();
+ UpdateIsReadyToPayAndNotifyObservers();
}
// Record the missing required payment fields when no complete payment
diff --git a/chromium/components/payments/content/payment_request_state.h b/chromium/components/payments/content/payment_request_state.h
index bab9c1ce1a5..9487b13a19e 100644
--- a/chromium/components/payments/content/payment_request_state.h
+++ b/chromium/components/payments/content/payment_request_state.h
@@ -24,6 +24,7 @@
#include "content/public/browser/payment_app_provider.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
+#include "url/origin.h"
namespace autofill {
class AutofillProfile;
@@ -32,6 +33,10 @@ class PersonalDataManager;
class RegionDataLoader;
} // namespace autofill
+namespace content {
+class RenderFrameHost;
+} // namespace content
+
namespace payments {
class ContentPaymentRequestDelegate;
@@ -111,8 +116,10 @@ class PaymentRequestState : public PaymentAppFactory::Delegate,
PaymentRequestState(
content::WebContents* web_contents,
+ content::RenderFrameHost* initiator_render_frame_host,
const GURL& top_level_origin,
const GURL& frame_origin,
+ const url::Origin& frame_security_origin,
PaymentRequestSpec* spec,
Delegate* delegate,
const std::string& app_locale,
@@ -124,10 +131,16 @@ class PaymentRequestState : public PaymentAppFactory::Delegate,
// PaymentAppFactory::Delegate
content::WebContents* GetWebContents() override;
- ContentPaymentRequestDelegate* GetPaymentRequestDelegate() override;
- PaymentRequestSpec* GetSpec() override;
+ ContentPaymentRequestDelegate* GetPaymentRequestDelegate() const override;
+ PaymentRequestSpec* GetSpec() const override;
const GURL& GetTopOrigin() override;
const GURL& GetFrameOrigin() override;
+ const url::Origin& GetFrameSecurityOrigin() override;
+ content::RenderFrameHost* GetInitiatorRenderFrameHost() const override;
+ const std::vector<mojom::PaymentMethodDataPtr>& GetMethodData()
+ const override;
+ scoped_refptr<PaymentManifestWebDataService>
+ GetPaymentManifestWebDataService() const override;
const std::vector<autofill::AutofillProfile*>& GetBillingProfiles() override;
bool IsRequestedAutofillDataAvailable() override;
bool MayCrawlForInstallablePaymentApps() override;
@@ -135,6 +148,11 @@ class PaymentRequestState : public PaymentAppFactory::Delegate,
int64_t registration_id) override;
void OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) override;
void OnPaymentAppCreationError(const std::string& error_message) override;
+ bool SkipCreatingNativePaymentApps() const override;
+ void OnCreatingNativePaymentAppsSkipped(
+ const content::PaymentAppProvider::PaymentApps& apps,
+ const ServiceWorkerPaymentAppFinder::InstallablePaymentApps&
+ installable_apps) override;
void OnDoneCreatingPaymentApps() override;
// PaymentResponseHelper::Delegate
@@ -160,6 +178,9 @@ class PaymentRequestState : public PaymentAppFactory::Delegate,
// "basic-card", but false for "https://bobpay.com".
void AreRequestedMethodsSupported(MethodsSupportedCallback callback);
+ // Resets pending MethodsSupportedCallback after abort.
+ void OnAbort();
+
// Returns authenticated user email, or empty string.
std::string GetAuthenticatedEmail() const;
@@ -330,8 +351,10 @@ class PaymentRequestState : public PaymentAppFactory::Delegate,
SectionSelectionStatus selection_status);
content::WebContents* web_contents_;
+ content::RenderFrameHost* initiator_render_frame_host_;
const GURL top_origin_;
const GURL frame_origin_;
+ const url::Origin frame_security_origin_;
size_t number_of_payment_app_factories_ = 0;
// True when the requested autofill data (shipping address and/or contact
diff --git a/chromium/components/payments/content/payment_request_state_unittest.cc b/chromium/components/payments/content/payment_request_state_unittest.cc
index f25dff519cf..7780428c267 100644
--- a/chromium/components/payments/content/payment_request_state_unittest.cc
+++ b/chromium/components/payments/content/payment_request_state_unittest.cc
@@ -80,10 +80,12 @@ class PaymentRequestStateTest : public testing::Test,
PaymentAppServiceFactory::SetForTesting(
std::make_unique<PaymentAppService>());
state_ = std::make_unique<PaymentRequestState>(
- /*web_contents=*/nullptr, GURL("https://example.com"),
- GURL("https://example.com/pay"), spec_.get(), this, "en-US",
- &test_personal_data_manager_, &test_payment_request_delegate_,
- base::Bind(
+ /*web_contents=*/nullptr,
+ /*render_frame_host=*/nullptr, GURL("https://example.com"),
+ GURL("https://example.com/pay"),
+ url::Origin::Create(GURL("https://example.com")), spec_.get(), this,
+ "en-US", &test_personal_data_manager_, &test_payment_request_delegate_,
+ base::BindRepeating(
[](const url::Origin& origin,
int64_t registration_id) { /* Intentionally left blank. */ }),
&journey_logger_);
diff --git a/chromium/components/payments/content/payment_response_helper_unittest.cc b/chromium/components/payments/content/payment_response_helper_unittest.cc
index 9bbecf2b74e..96c67a2ffaf 100644
--- a/chromium/components/payments/content/payment_response_helper_unittest.cc
+++ b/chromium/components/payments/content/payment_response_helper_unittest.cc
@@ -33,12 +33,12 @@ class PaymentResponseHelperTest : public testing::Test,
test_personal_data_manager_.AddProfile(address_);
// Set up the autofill payment app.
- autofill::CreditCard visa_card = autofill::test::GetCreditCard();
- visa_card.set_billing_address_id(address_.guid());
- visa_card.set_use_count(5u);
+ visa_card_ = autofill::test::GetCreditCard();
+ visa_card_.set_billing_address_id(address_.guid());
+ visa_card_.set_use_count(5u);
autofill_app_ = std::make_unique<AutofillPaymentApp>(
- "visa", visa_card, /*matches_merchant_card_type_exactly=*/true,
- billing_addresses_, "en-US", &test_payment_request_delegate_);
+ "visa", visa_card_, billing_addresses_, "en-US",
+ &test_payment_request_delegate_);
}
~PaymentResponseHelperTest() override {}
@@ -90,6 +90,7 @@ class PaymentResponseHelperTest : public testing::Test,
PaymentRequestSpec* spec() { return spec_.get(); }
const mojom::PaymentResponsePtr& response() { return payment_response_; }
autofill::AutofillProfile* test_address() { return &address_; }
+ const autofill::CreditCard& test_credit_card() { return visa_card_; }
PaymentApp* test_app() { return autofill_app_.get(); }
PaymentRequestDelegate* test_payment_request_delegate() {
return &test_payment_request_delegate_;
@@ -103,6 +104,7 @@ class PaymentResponseHelperTest : public testing::Test,
// Test data.
autofill::AutofillProfile address_;
+ autofill::CreditCard visa_card_;
const std::vector<autofill::AutofillProfile*> billing_addresses_;
std::unique_ptr<AutofillPaymentApp> autofill_app_;
};
@@ -119,22 +121,27 @@ TEST_F(PaymentResponseHelperTest, GeneratePaymentResponse_SupportedMethod) {
test_address(), this);
EXPECT_EQ("visa", response()->method_name);
EXPECT_EQ(
- "{\"billingAddress\":"
- "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
- "\"city\":\"Elysium\","
- "\"country\":\"US\","
- "\"dependentLocality\":\"\","
- "\"organization\":\"Underworld\","
- "\"phone\":\"16502111111\","
- "\"postalCode\":\"91111\","
- "\"recipient\":\"John H. Doe\","
- "\"region\":\"CA\","
- "\"sortingCode\":\"\"},"
- "\"cardNumber\":\"4111111111111111\","
- "\"cardSecurityCode\":\"123\","
- "\"cardholderName\":\"Test User\","
- "\"expiryMonth\":\"11\","
- "\"expiryYear\":\"2022\"}",
+ base::StringPrintf(
+ "{\"billingAddress\":"
+ "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
+ "\"city\":\"Elysium\","
+ "\"country\":\"US\","
+ "\"dependentLocality\":\"\","
+ "\"organization\":\"Underworld\","
+ "\"phone\":\"16502111111\","
+ "\"postalCode\":\"91111\","
+ "\"recipient\":\"John H. Doe\","
+ "\"region\":\"CA\","
+ "\"sortingCode\":\"\"},"
+ "\"cardNumber\":\"4111111111111111\","
+ "\"cardSecurityCode\":\"123\","
+ "\"cardholderName\":\"Test User\","
+ "\"expiryMonth\":\"%s\","
+ "\"expiryYear\":\"%s\"}",
+ base::UTF16ToUTF8(test_credit_card().Expiration2DigitMonthAsString())
+ .c_str(),
+ base::UTF16ToUTF8(test_credit_card().Expiration4DigitYearAsString())
+ .c_str()),
response()->stringified_details);
}
@@ -157,22 +164,27 @@ TEST_F(PaymentResponseHelperTest, GeneratePaymentResponse_BasicCard) {
test_address(), this);
EXPECT_EQ("basic-card", response()->method_name);
EXPECT_EQ(
- "{\"billingAddress\":"
- "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
- "\"city\":\"Elysium\","
- "\"country\":\"US\","
- "\"dependentLocality\":\"\","
- "\"organization\":\"Underworld\","
- "\"phone\":\"16502111111\","
- "\"postalCode\":\"91111\","
- "\"recipient\":\"John H. Doe\","
- "\"region\":\"CA\","
- "\"sortingCode\":\"\"},"
- "\"cardNumber\":\"4111111111111111\","
- "\"cardSecurityCode\":\"123\","
- "\"cardholderName\":\"Test User\","
- "\"expiryMonth\":\"11\","
- "\"expiryYear\":\"2022\"}",
+ base::StringPrintf(
+ "{\"billingAddress\":"
+ "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
+ "\"city\":\"Elysium\","
+ "\"country\":\"US\","
+ "\"dependentLocality\":\"\","
+ "\"organization\":\"Underworld\","
+ "\"phone\":\"16502111111\","
+ "\"postalCode\":\"91111\","
+ "\"recipient\":\"John H. Doe\","
+ "\"region\":\"CA\","
+ "\"sortingCode\":\"\"},"
+ "\"cardNumber\":\"4111111111111111\","
+ "\"cardSecurityCode\":\"123\","
+ "\"cardholderName\":\"Test User\","
+ "\"expiryMonth\":\"%s\","
+ "\"expiryYear\":\"%s\"}",
+ base::UTF16ToUTF8(test_credit_card().Expiration2DigitMonthAsString())
+ .c_str(),
+ base::UTF16ToUTF8(test_credit_card().Expiration4DigitYearAsString())
+ .c_str()),
response()->stringified_details);
}
diff --git a/chromium/components/payments/content/service_worker_payment_app.cc b/chromium/components/payments/content/service_worker_payment_app.cc
index 40cfdedba99..c6b87b07d70 100644
--- a/chromium/components/payments/content/service_worker_payment_app.cc
+++ b/chromium/components/payments/content/service_worker_payment_app.cc
@@ -10,10 +10,12 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/feature_list.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/payments/content/payment_event_response_util.h"
#include "components/payments/content/payment_request_converter.h"
+#include "components/payments/core/features.h"
#include "components/payments/core/method_strings.h"
#include "components/payments/core/payment_request_delegate.h"
#include "content/public/browser/browser_context.h"
@@ -180,6 +182,8 @@ ServiceWorkerPaymentApp::CreateCanMakePaymentEventData() {
event_data->top_origin = top_origin_;
event_data->payment_request_origin = frame_origin_;
+ if (base::FeatureList::IsEnabled(::features::kWebPaymentsMinimalUI))
+ event_data->currency = spec_->details().total->amount->currency;
DCHECK(spec_->details().modifiers);
for (const auto& modifier : *spec_->details().modifiers) {
@@ -210,10 +214,10 @@ void ServiceWorkerPaymentApp::OnCanMakePaymentEventSkipped(
void ServiceWorkerPaymentApp::OnCanMakePaymentEventResponded(
ValidateCanMakePaymentCallback callback,
- bool result) {
+ mojom::CanMakePaymentResponsePtr response) {
// |can_make_payment| is true as long as there is a matching payment handler.
can_make_payment_result_ = true;
- has_enrolled_instrument_result_ = result;
+ has_enrolled_instrument_result_ = response->can_make_payment;
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), this, can_make_payment_result_));
@@ -389,16 +393,12 @@ bool ServiceWorkerPaymentApp::CanPreselect() const {
return !GetLabel().empty() && !icon_image_.size().IsEmpty();
}
-bool ServiceWorkerPaymentApp::IsExactlyMatchingMerchantRequest() const {
- return true;
-}
-
base::string16 ServiceWorkerPaymentApp::GetMissingInfoLabel() const {
NOTREACHED();
return base::string16();
}
-bool ServiceWorkerPaymentApp::IsValidForCanMakePayment() const {
+bool ServiceWorkerPaymentApp::HasEnrolledInstrument() const {
// This app should not be used when can_make_payment_result_ is false, so this
// interface should not be invoked.
DCHECK(can_make_payment_result_);
@@ -409,6 +409,10 @@ void ServiceWorkerPaymentApp::RecordUse() {
NOTIMPLEMENTED();
}
+bool ServiceWorkerPaymentApp::NeedsInstallation() const {
+ return needs_installation_;
+}
+
base::string16 ServiceWorkerPaymentApp::GetLabel() const {
return base::UTF8ToUTF16(needs_installation_
? installable_web_app_info_->name
@@ -428,9 +432,7 @@ base::string16 ServiceWorkerPaymentApp::GetSublabel() const {
bool ServiceWorkerPaymentApp::IsValidForModifier(
const std::string& method,
bool supported_networks_specified,
- const std::set<std::string>& supported_networks,
- bool supported_types_specified,
- const std::set<autofill::CreditCard::CardType>& supported_types) const {
+ const std::set<std::string>& supported_networks) const {
// Payment app that needs installation only supports url based payment
// methods.
if (needs_installation_)
@@ -447,9 +449,8 @@ bool ServiceWorkerPaymentApp::IsValidForModifier(
return true;
// Checking the capabilities of this app against the modifier.
- // Return true if both card networks and types are not specified in the
- // modifier.
- if (!supported_networks_specified && !supported_types_specified)
+ // Return true if card networks are not specified in the modifier.
+ if (!supported_networks_specified)
return true;
// Return false if no capabilities for this app.
@@ -473,21 +474,6 @@ bool ServiceWorkerPaymentApp::IsValidForModifier(
}
}
- if (supported_types_specified) {
- std::set<autofill::CreditCard::CardType> app_supported_types;
- for (const auto& type :
- stored_payment_app_info_->capabilities[i].supported_card_types) {
- app_supported_types.insert(
- GetBasicCardType(static_cast<mojom::BasicCardType>(type)));
- }
-
- if (base::STLSetIntersection<std::set<autofill::CreditCard::CardType>>(
- app_supported_types, supported_types)
- .empty()) {
- continue;
- }
- }
-
break;
}
@@ -545,4 +531,19 @@ void ServiceWorkerPaymentApp::OnPaymentAppIdentity(const url::Origin& origin,
identity_callback_.Run(origin, registration_id);
}
+ukm::SourceId ServiceWorkerPaymentApp::UkmSourceId() {
+ if (ukm_source_id_ == ukm::kInvalidSourceId) {
+ GURL sw_scope = needs_installation_
+ ? GURL(installable_web_app_info_->sw_scope)
+ : stored_payment_app_info_->scope;
+ // At this point we know that the payment handler window is open for this
+ // app since this getter is called for the invoked app inside the
+ // PaymentRequest::OnPaymentHandlerOpenWindowCalled function.
+ ukm_source_id_ =
+ content::PaymentAppProvider::GetInstance()
+ ->GetSourceIdForPaymentAppFromScope(sw_scope.GetOrigin());
+ }
+ return ukm_source_id_;
+}
+
} // namespace payments
diff --git a/chromium/components/payments/content/service_worker_payment_app.h b/chromium/components/payments/content/service_worker_payment_app.h
index 03e09ad547f..f6e5130038f 100644
--- a/chromium/components/payments/content/service_worker_payment_app.h
+++ b/chromium/components/payments/content/service_worker_payment_app.h
@@ -81,24 +81,23 @@ class ServiceWorkerPaymentApp : public PaymentApp {
bool IsCompleteForPayment() const override;
uint32_t GetCompletenessScore() const override;
bool CanPreselect() const override;
- bool IsExactlyMatchingMerchantRequest() const override;
base::string16 GetMissingInfoLabel() const override;
- bool IsValidForCanMakePayment() const override;
+ bool HasEnrolledInstrument() const override;
void RecordUse() override;
+ bool NeedsInstallation() const override;
base::string16 GetLabel() const override;
base::string16 GetSublabel() const override;
- bool IsValidForModifier(const std::string& method,
- bool supported_networks_specified,
- const std::set<std::string>& supported_networks,
- bool supported_types_specified,
- const std::set<autofill::CreditCard::CardType>&
- supported_types) const override;
+ bool IsValidForModifier(
+ const std::string& method,
+ bool supported_networks_specified,
+ const std::set<std::string>& supported_networks) const override;
base::WeakPtr<PaymentApp> AsWeakPtr() override;
gfx::ImageSkia icon_image_skia() const override;
bool HandlesShippingAddress() const override;
bool HandlesPayerName() const override;
bool HandlesPayerEmail() const override;
bool HandlesPayerPhone() const override;
+ ukm::SourceId UkmSourceId() override;
void set_payment_handler_host(
mojo::PendingRemote<mojom::PaymentHandlerHost> payment_handler_host) {
@@ -113,8 +112,9 @@ class ServiceWorkerPaymentApp : public PaymentApp {
mojom::CanMakePaymentEventDataPtr CreateCanMakePaymentEventData();
void OnCanMakePaymentEventSkipped(ValidateCanMakePaymentCallback callback);
- void OnCanMakePaymentEventResponded(ValidateCanMakePaymentCallback callback,
- bool result);
+ void OnCanMakePaymentEventResponded(
+ ValidateCanMakePaymentCallback callback,
+ mojom::CanMakePaymentResponsePtr response);
// Called from two places:
// 1) From PaymentAppProvider after a just-in-time installable payment handler
@@ -154,6 +154,8 @@ class ServiceWorkerPaymentApp : public PaymentApp {
std::unique_ptr<WebAppInstallationInfo> installable_web_app_info_;
std::string installable_enabled_method_;
+ ukm::SourceId ukm_source_id_ = ukm::kInvalidSourceId;
+
base::WeakPtrFactory<ServiceWorkerPaymentApp> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPaymentApp);
diff --git a/chromium/components/payments/content/service_worker_payment_app_factory.cc b/chromium/components/payments/content/service_worker_payment_app_factory.cc
index fe0caf312d8..047613adb64 100644
--- a/chromium/components/payments/content/service_worker_payment_app_factory.cc
+++ b/chromium/components/payments/content/service_worker_payment_app_factory.cc
@@ -17,6 +17,18 @@
#include "content/public/browser/web_contents.h"
namespace payments {
+namespace {
+
+std::vector<mojom::PaymentMethodDataPtr> Clone(
+ const std::vector<mojom::PaymentMethodDataPtr>& original) {
+ std::vector<mojom::PaymentMethodDataPtr> clone(original.size());
+ std::transform(
+ original.begin(), original.end(), clone.begin(),
+ [](const mojom::PaymentMethodDataPtr& item) { return item.Clone(); });
+ return clone;
+}
+
+} // namespace
class ServiceWorkerPaymentAppCreator {
public:
@@ -45,14 +57,21 @@ class ServiceWorkerPaymentAppCreator {
return;
}
+ if (delegate_->SkipCreatingNativePaymentApps()) {
+ delegate_->OnCreatingNativePaymentAppsSkipped(
+ std::move(apps), std::move(installable_apps));
+ FinishAndCleanup();
+ return;
+ }
+
for (auto& installed_app : apps) {
auto app = std::make_unique<ServiceWorkerPaymentApp>(
delegate_->GetWebContents()->GetBrowserContext(),
delegate_->GetTopOrigin(), delegate_->GetFrameOrigin(),
delegate_->GetSpec(), std::move(installed_app.second),
delegate_->GetPaymentRequestDelegate(),
- base::Bind(&PaymentAppFactory::Delegate::OnPaymentAppInstalled,
- delegate_));
+ base::BindRepeating(
+ &PaymentAppFactory::Delegate::OnPaymentAppInstalled, delegate_));
app->ValidateCanMakePayment(base::BindOnce(
&ServiceWorkerPaymentAppCreator::OnSWPaymentAppValidated,
weak_ptr_factory_.GetWeakPtr()));
@@ -66,8 +85,8 @@ class ServiceWorkerPaymentAppCreator {
delegate_->GetFrameOrigin(), delegate_->GetSpec(),
std::move(installable_app.second), installable_app.first.spec(),
delegate_->GetPaymentRequestDelegate(),
- base::Bind(&PaymentAppFactory::Delegate::OnPaymentAppInstalled,
- delegate_));
+ base::BindRepeating(
+ &PaymentAppFactory::Delegate::OnPaymentAppInstalled, delegate_));
app->ValidateCanMakePayment(base::BindOnce(
&ServiceWorkerPaymentAppCreator::OnSWPaymentAppValidated,
weak_ptr_factory_.GetWeakPtr()));
@@ -125,13 +144,15 @@ void ServiceWorkerPaymentAppFactory::Create(base::WeakPtr<Delegate> delegate) {
/*owner=*/this, delegate);
ServiceWorkerPaymentAppCreator* creator_raw_pointer = creator.get();
creators_[creator_raw_pointer] = std::move(creator);
+
ServiceWorkerPaymentAppFinder::GetInstance()->GetAllPaymentApps(
- delegate->GetWebContents(),
- delegate->GetPaymentRequestDelegate()->GetPaymentManifestWebDataService(),
- delegate->GetSpec()->method_data(),
+ delegate->GetFrameSecurityOrigin(),
+ delegate->GetInitiatorRenderFrameHost(), delegate->GetWebContents(),
+ delegate->GetPaymentManifestWebDataService(),
+ Clone(delegate->GetMethodData()),
delegate->MayCrawlForInstallablePaymentApps(),
- base::Bind(&ServiceWorkerPaymentAppCreator::CreatePaymentApps,
- creator_raw_pointer->GetWeakPtr()),
+ base::BindOnce(&ServiceWorkerPaymentAppCreator::CreatePaymentApps,
+ creator_raw_pointer->GetWeakPtr()),
base::BindOnce([]() {
// Nothing needs to be done after writing cache. This callback is used
// only in tests.
diff --git a/chromium/components/payments/content/service_worker_payment_app_finder.cc b/chromium/components/payments/content/service_worker_payment_app_finder.cc
index d2a0e89e315..72c000a627c 100644
--- a/chromium/components/payments/content/service_worker_payment_app_finder.cc
+++ b/chromium/components/payments/content/service_worker_payment_app_finder.cc
@@ -24,6 +24,7 @@
#include "components/payments/core/payment_manifest_downloader.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/stored_payment_app.h"
#include "content/public/browser/web_contents.h"
@@ -54,14 +55,11 @@ bool BasicCardCapabilitiesMatch(
const mojom::PaymentMethodDataPtr& request) {
for (const auto& capability : capabilities) {
if (CapabilityMatches(request->supported_networks,
- capability.supported_card_networks) &&
- CapabilityMatches(request->supported_types,
- capability.supported_card_types)) {
+ capability.supported_card_networks)) {
return true;
}
}
- return capabilities.empty() && request->supported_networks.empty() &&
- request->supported_types.empty();
+ return capabilities.empty() && request->supported_networks.empty();
}
// Returns true if |app| supports at least one of the |requests|.
@@ -101,6 +99,8 @@ class SelfDeletingServiceWorkerPaymentAppFinder {
// this factory. Don't destroy the factory and don't call this method again
// until |finished_using_resources_callback| has run.
void GetAllPaymentApps(
+ const url::Origin& merchant_origin,
+ content::RenderFrameHost* initiator_render_frame_host,
content::WebContents* web_contents,
std::unique_ptr<PaymentManifestDownloader> downloader,
scoped_refptr<PaymentManifestWebDataService> cache,
@@ -115,13 +115,15 @@ class SelfDeletingServiceWorkerPaymentAppFinder {
std::make_unique<DeveloperConsoleLogger>(web_contents));
cache_ = cache;
verifier_ = std::make_unique<ManifestVerifier>(
- web_contents, downloader_.get(), parser_.get(), cache_.get());
+ merchant_origin, web_contents, downloader_.get(), parser_.get(),
+ cache_.get());
if (may_crawl_for_installable_payment_apps &&
base::FeatureList::IsEnabled(
features::kWebPaymentsJustInTimePaymentApp)) {
// Construct crawler in constructor to allow it observe the web_contents.
crawler_ = std::make_unique<InstallablePaymentAppCrawler>(
- web_contents, downloader_.get(), parser_.get(), cache_.get());
+ merchant_origin, initiator_render_frame_host, web_contents,
+ downloader_.get(), parser_.get(), cache_.get());
if (ignore_port_in_origin_comparison_for_testing_)
crawler_->IgnorePortInOriginComparisonForTesting();
}
@@ -147,10 +149,27 @@ class SelfDeletingServiceWorkerPaymentAppFinder {
}
private:
+ static void RemoveUnrequestedMethods(
+ const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data,
+ content::PaymentAppProvider::PaymentApps* apps) {
+ std::set<std::string> requested_methods;
+ for (const auto& requested_method_datum : requested_method_data) {
+ requested_methods.insert(requested_method_datum->supported_method);
+ }
+ for (auto& app : *apps) {
+ std::sort(app.second->enabled_methods.begin(),
+ app.second->enabled_methods.end());
+ app.second->enabled_methods =
+ base::STLSetIntersection<std::vector<std::string>>(
+ app.second->enabled_methods, requested_methods);
+ }
+ }
+
void OnGotAllPaymentApps(content::PaymentAppProvider::PaymentApps apps) {
if (ignore_port_in_origin_comparison_for_testing_)
RemovePortNumbersFromScopesForTest(&apps);
+ RemoveUnrequestedMethods(requested_method_data_, &apps);
ServiceWorkerPaymentAppFinder::RemoveAppsWithoutMatchingMethodData(
requested_method_data_, &apps);
if (apps.empty()) {
@@ -266,15 +285,31 @@ ServiceWorkerPaymentAppFinder* ServiceWorkerPaymentAppFinder::GetInstance() {
}
void ServiceWorkerPaymentAppFinder::GetAllPaymentApps(
+ const url::Origin& merchant_origin,
+ content::RenderFrameHost* initiator_render_frame_host,
content::WebContents* web_contents,
scoped_refptr<PaymentManifestWebDataService> cache,
- const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data,
+ std::vector<mojom::PaymentMethodDataPtr> requested_method_data,
bool may_crawl_for_installable_payment_apps,
GetAllPaymentAppsCallback callback,
base::OnceClosure finished_writing_cache_callback_for_testing) {
+ DCHECK(!requested_method_data.empty());
+ // Do not look up payment handlers for ignored payment methods.
+ base::EraseIf(requested_method_data,
+ [&](const mojom::PaymentMethodDataPtr& method_data) {
+ return base::Contains(ignored_methods_,
+ method_data->supported_method);
+ });
+ if (requested_method_data.empty()) {
+ std::move(callback).Run(
+ content::PaymentAppProvider::PaymentApps(),
+ std::map<GURL, std::unique_ptr<WebAppInstallationInfo>>(),
+ /*error_message=*/"");
+ return;
+ }
+
SelfDeletingServiceWorkerPaymentAppFinder* self_delete_factory =
new SelfDeletingServiceWorkerPaymentAppFinder();
-
std::unique_ptr<PaymentManifestDownloader> downloader;
if (test_downloader_ != nullptr) {
downloader = std::move(test_downloader_);
@@ -288,7 +323,8 @@ void ServiceWorkerPaymentAppFinder::GetAllPaymentApps(
}
self_delete_factory->GetAllPaymentApps(
- web_contents, std::move(downloader), cache, requested_method_data,
+ merchant_origin, initiator_render_frame_host, web_contents,
+ std::move(downloader), cache, requested_method_data,
may_crawl_for_installable_payment_apps, std::move(callback),
std::move(finished_writing_cache_callback_for_testing));
}
@@ -307,10 +343,16 @@ void ServiceWorkerPaymentAppFinder::RemoveAppsWithoutMatchingMethodData(
}
}
+void ServiceWorkerPaymentAppFinder::IgnorePaymentMethodForTest(
+ const std::string& method) {
+ ignored_methods_.insert(method);
+}
+
ServiceWorkerPaymentAppFinder::ServiceWorkerPaymentAppFinder()
- : test_downloader_(nullptr) {}
+ : ignored_methods_({methods::kGooglePlayBilling}),
+ test_downloader_(nullptr) {}
-ServiceWorkerPaymentAppFinder::~ServiceWorkerPaymentAppFinder() {}
+ServiceWorkerPaymentAppFinder::~ServiceWorkerPaymentAppFinder() = default;
void ServiceWorkerPaymentAppFinder::
SetDownloaderAndIgnorePortInOriginComparisonForTesting(
diff --git a/chromium/components/payments/content/service_worker_payment_app_finder.h b/chromium/components/payments/content/service_worker_payment_app_finder.h
index 4a726a32829..04d7fa64147 100644
--- a/chromium/components/payments/content/service_worker_payment_app_finder.h
+++ b/chromium/components/payments/content/service_worker_payment_app_finder.h
@@ -27,9 +27,14 @@ struct DefaultSingletonTraits;
} // namespace base
namespace content {
+class RenderFrameHost;
class WebContents;
} // namespace content
+namespace url {
+class Origin;
+} // namespace url
+
namespace payments {
class PaymentManifestDownloader;
@@ -51,6 +56,10 @@ class ServiceWorkerPaymentAppFinder {
// |requested_method_data|, verifies these apps are allowed to handle these
// payment methods, and filters them by their capabilities.
//
+ // |merchant_origin| should be the origin of the iframe that created the
+ // PaymentRequest object. It is used by security features like
+ // 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'.
+ //
// The payment apps will be returned through |callback|. After |callback| has
// been invoked, it's safe to show the apps in UI for user to select one of
// these apps for payment.
@@ -61,9 +70,11 @@ class ServiceWorkerPaymentAppFinder {
//
// The method should be called on the UI thread.
void GetAllPaymentApps(
+ const url::Origin& merchant_origin,
+ content::RenderFrameHost* initiator_render_frame_host,
content::WebContents* web_contents,
scoped_refptr<PaymentManifestWebDataService> cache,
- const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data,
+ std::vector<mojom::PaymentMethodDataPtr> requested_method_data,
bool may_crawl_for_installable_payment_apps,
GetAllPaymentAppsCallback callback,
base::OnceClosure finished_writing_cache_callback_for_testing);
@@ -74,13 +85,16 @@ class ServiceWorkerPaymentAppFinder {
const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data,
content::PaymentAppProvider::PaymentApps* apps);
+ // Ignore the given |method|, so that no installed or installable service
+ // workers would ever be looked up in GetAllPaymentApps(). Calling this
+ // multiple times will union the new payment methods with the existing set.
+ void IgnorePaymentMethodForTest(const std::string& method);
+
private:
friend struct base::DefaultSingletonTraits<ServiceWorkerPaymentAppFinder>;
friend class PaymentRequestPaymentAppTest;
friend class ServiceWorkerPaymentAppFinderBrowserTest;
- friend class HybridRequestSkipUITest;
- friend class JourneyLoggerTest;
- friend class PaymentHandlerJustInTimeInstallationTest;
+ friend class PaymentRequestPlatformBrowserTestBase;
ServiceWorkerPaymentAppFinder();
~ServiceWorkerPaymentAppFinder();
@@ -91,6 +105,7 @@ class ServiceWorkerPaymentAppFinder {
void SetDownloaderAndIgnorePortInOriginComparisonForTesting(
std::unique_ptr<PaymentManifestDownloader> downloader);
+ std::set<std::string> ignored_methods_;
std::unique_ptr<PaymentManifestDownloader> test_downloader_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPaymentAppFinder);
diff --git a/chromium/components/payments/content/service_worker_payment_app_finder_unittest.cc b/chromium/components/payments/content/service_worker_payment_app_finder_unittest.cc
index b673962574e..32ab27500ca 100644
--- a/chromium/components/payments/content/service_worker_payment_app_finder_unittest.cc
+++ b/chromium/components/payments/content/service_worker_payment_app_finder_unittest.cc
@@ -105,21 +105,6 @@ TEST_F(ServiceWorkerPaymentAppFinderTest,
}
TEST_F(ServiceWorkerPaymentAppFinderTest,
- RemoveAppsWithoutMatchingMethodData_NoTypeCapabilities) {
- std::vector<mojom::PaymentMethodDataPtr> requested_methods;
- requested_methods.emplace_back(mojom::PaymentMethodData::New());
- requested_methods.back()->supported_method = "basic-card";
- requested_methods.back()->supported_types = {mojom::BasicCardType::DEBIT};
- content::PaymentAppProvider::PaymentApps apps;
- apps[0] = std::make_unique<content::StoredPaymentApp>();
- apps[0]->enabled_methods = {"basic-card"};
-
- RemoveAppsWithoutMatchingMethodData(requested_methods, &apps);
-
- EXPECT_TRUE(apps.empty());
-}
-
-TEST_F(ServiceWorkerPaymentAppFinderTest,
RemoveAppsWithoutMatchingMethodData_NoMatchingNetworkCapabilities) {
std::vector<mojom::PaymentMethodDataPtr> requested_methods;
requested_methods.emplace_back(mojom::PaymentMethodData::New());
@@ -139,25 +124,7 @@ TEST_F(ServiceWorkerPaymentAppFinderTest,
}
TEST_F(ServiceWorkerPaymentAppFinderTest,
- RemoveAppsWithoutMatchingMethodData_NoMatchingTypeCapabilities) {
- std::vector<mojom::PaymentMethodDataPtr> requested_methods;
- requested_methods.emplace_back(mojom::PaymentMethodData::New());
- requested_methods.back()->supported_method = "basic-card";
- requested_methods.back()->supported_types = {mojom::BasicCardType::DEBIT};
- content::PaymentAppProvider::PaymentApps apps;
- apps[0] = std::make_unique<content::StoredPaymentApp>();
- apps[0]->enabled_methods = {"basic-card"};
- apps[0]->capabilities.emplace_back();
- apps[0]->capabilities.back().supported_card_types = {
- static_cast<int32_t>(mojom::BasicCardType::CREDIT)};
-
- RemoveAppsWithoutMatchingMethodData(requested_methods, &apps);
-
- EXPECT_TRUE(apps.empty());
-}
-
-TEST_F(ServiceWorkerPaymentAppFinderTest,
- RemoveAppsWithoutMatchingMethodData_NoRequestedNetworkOrType) {
+ RemoveAppsWithoutMatchingMethodData_NoRequestedNetwork) {
std::vector<mojom::PaymentMethodDataPtr> requested_methods;
requested_methods.emplace_back(mojom::PaymentMethodData::New());
requested_methods.back()->supported_method = "basic-card";
@@ -167,8 +134,6 @@ TEST_F(ServiceWorkerPaymentAppFinderTest,
apps[0]->capabilities.emplace_back();
apps[0]->capabilities.back().supported_card_networks = {
static_cast<int32_t>(mojom::BasicCardNetwork::VISA)};
- apps[0]->capabilities.back().supported_card_types = {
- static_cast<int32_t>(mojom::BasicCardType::CREDIT)};
RemoveAppsWithoutMatchingMethodData(requested_methods, &apps);
@@ -178,21 +143,16 @@ TEST_F(ServiceWorkerPaymentAppFinderTest,
EXPECT_EQ(std::vector<std::string>{"basic-card"}, actual->enabled_methods);
ASSERT_EQ(1U, actual->capabilities.size());
const auto& capability = actual->capabilities.back();
- ASSERT_EQ(1U, capability.supported_card_types.size());
- EXPECT_EQ(static_cast<int32_t>(mojom::BasicCardType::CREDIT),
- capability.supported_card_types[0]);
ASSERT_EQ(1U, actual->capabilities.back().supported_card_networks.size());
EXPECT_EQ(static_cast<int32_t>(mojom::BasicCardNetwork::VISA),
capability.supported_card_networks[0]);
}
TEST_F(ServiceWorkerPaymentAppFinderTest,
- RemoveAppsWithoutMatchingMethodData_IntersectionOfNetworksAndTypes) {
+ RemoveAppsWithoutMatchingMethodData_IntersectionOfNetworks) {
std::vector<mojom::PaymentMethodDataPtr> requested_methods;
requested_methods.emplace_back(mojom::PaymentMethodData::New());
requested_methods.back()->supported_method = "basic-card";
- requested_methods.back()->supported_types = {mojom::BasicCardType::DEBIT,
- mojom::BasicCardType::CREDIT};
requested_methods.back()->supported_networks = {
mojom::BasicCardNetwork::AMEX, mojom::BasicCardNetwork::DINERS};
content::PaymentAppProvider::PaymentApps apps;
@@ -202,9 +162,6 @@ TEST_F(ServiceWorkerPaymentAppFinderTest,
apps[0]->capabilities.back().supported_card_networks = {
static_cast<int32_t>(mojom::BasicCardNetwork::DINERS),
static_cast<int32_t>(mojom::BasicCardNetwork::VISA)};
- apps[0]->capabilities.back().supported_card_types = {
- static_cast<int32_t>(mojom::BasicCardType::PREPAID),
- static_cast<int32_t>(mojom::BasicCardType::DEBIT)};
RemoveAppsWithoutMatchingMethodData(requested_methods, &apps);
@@ -214,10 +171,6 @@ TEST_F(ServiceWorkerPaymentAppFinderTest,
EXPECT_EQ(std::vector<std::string>{"basic-card"}, actual->enabled_methods);
ASSERT_EQ(1U, actual->capabilities.size());
const auto& capability = actual->capabilities.back();
- EXPECT_EQ(
- (std::vector<int32_t>{static_cast<int32_t>(mojom::BasicCardType::PREPAID),
- static_cast<int32_t>(mojom::BasicCardType::DEBIT)}),
- capability.supported_card_types);
EXPECT_EQ((std::vector<int32_t>{
static_cast<int32_t>(mojom::BasicCardNetwork::DINERS),
static_cast<int32_t>(mojom::BasicCardNetwork::VISA)}),
@@ -229,13 +182,10 @@ TEST_F(ServiceWorkerPaymentAppFinderTest,
std::vector<mojom::PaymentMethodDataPtr> requested_methods;
requested_methods.emplace_back(mojom::PaymentMethodData::New());
requested_methods.back()->supported_method = "unknown-method";
- requested_methods.back()->supported_types = {mojom::BasicCardType::DEBIT};
content::PaymentAppProvider::PaymentApps apps;
apps[0] = std::make_unique<content::StoredPaymentApp>();
apps[0]->enabled_methods = {"unknown-method"};
apps[0]->capabilities.emplace_back();
- apps[0]->capabilities.back().supported_card_types = {
- static_cast<int32_t>(mojom::BasicCardType::PREPAID)};
RemoveAppsWithoutMatchingMethodData(requested_methods, &apps);
diff --git a/chromium/components/payments/content/service_worker_payment_app_unittest.cc b/chromium/components/payments/content/service_worker_payment_app_unittest.cc
index 2347f1e06de..3128121c1ab 100644
--- a/chromium/components/payments/content/service_worker_payment_app_unittest.cc
+++ b/chromium/components/payments/content/service_worker_payment_app_unittest.cc
@@ -76,7 +76,6 @@ class ServiceWorkerPaymentAppTest : public testing::Test,
entry_1->supported_networks.push_back(mojom::BasicCardNetwork::UNIONPAY);
entry_1->supported_networks.push_back(mojom::BasicCardNetwork::JCB);
entry_1->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
- entry_1->supported_types.push_back(mojom::BasicCardType::DEBIT);
method_data.push_back(std::move(entry_1));
mojom::PaymentMethodDataPtr entry_2 = mojom::PaymentMethodData::New();
@@ -109,8 +108,6 @@ class ServiceWorkerPaymentAppTest : public testing::Test,
static_cast<int32_t>(mojom::BasicCardNetwork::UNIONPAY));
stored_app->capabilities.back().supported_card_networks.emplace_back(
static_cast<int32_t>(mojom::BasicCardNetwork::JCB));
- stored_app->capabilities.back().supported_card_types.emplace_back(
- static_cast<int32_t>(mojom::BasicCardType::DEBIT));
stored_app->user_hint = "Visa 4012 ... 1881";
stored_app->prefer_related_applications = false;
@@ -119,7 +116,7 @@ class ServiceWorkerPaymentAppTest : public testing::Test,
&browser_context_, GURL("https://testmerchant.com"),
GURL("https://testmerchant.com/bobpay"), spec_.get(),
std::move(stored_app), &delegate_,
- base::Bind(
+ base::BindRepeating(
[](const url::Origin& origin,
int64_t registration_id) { /* Intentionally left blank. */ }));
}
@@ -151,7 +148,6 @@ TEST_F(ServiceWorkerPaymentAppTest, AppInfo) {
CreateServiceWorkerPaymentApp(true);
EXPECT_TRUE(GetApp()->IsCompleteForPayment());
- EXPECT_TRUE(GetApp()->IsExactlyMatchingMerchantRequest());
EXPECT_EQ(base::UTF16ToUTF8(GetApp()->GetLabel()), "bobpay");
EXPECT_EQ(base::UTF16ToUTF8(GetApp()->GetSublabel()), "bobpay.com");
@@ -176,7 +172,6 @@ TEST_F(ServiceWorkerPaymentAppTest, CreatePaymentRequestEventData) {
EXPECT_EQ(event_data->method_data.size(), 2U);
EXPECT_EQ(event_data->method_data[0]->supported_method, "basic-card");
EXPECT_EQ(event_data->method_data[0]->supported_networks.size(), 3U);
- EXPECT_EQ(event_data->method_data[0]->supported_types.size(), 1U);
EXPECT_EQ(event_data->method_data[1]->supported_method, "https://bobpay.com");
EXPECT_EQ(event_data->total->currency, "USD");
@@ -228,32 +223,28 @@ TEST_F(ServiceWorkerPaymentAppTest, ValidateCanMakePayment) {
CreateServiceWorkerPaymentApp(/*with_url_method=*/true);
GetApp()->ValidateCanMakePayment(base::BindOnce(
[](ServiceWorkerPaymentApp*, bool result) { EXPECT_TRUE(result); }));
- EXPECT_FALSE(GetApp()->IsValidForCanMakePayment());
+ EXPECT_FALSE(GetApp()->HasEnrolledInstrument());
}
// Test modifiers can be matched based on capabilities.
TEST_F(ServiceWorkerPaymentAppTest, IsValidForModifier) {
CreateServiceWorkerPaymentApp(true);
- EXPECT_TRUE(GetApp()->IsValidForModifier("basic-card", false, {}, false, {}));
-
- EXPECT_TRUE(
- GetApp()->IsValidForModifier("https://bobpay.com", true, {}, true, {}));
-
- EXPECT_FALSE(GetApp()->IsValidForModifier("basic-card", true, {"mastercard"},
- false, {}));
-
- EXPECT_TRUE(GetApp()->IsValidForModifier("basic-card", true, {"unionpay"},
- false, {}));
+ EXPECT_TRUE(GetApp()->IsValidForModifier(
+ /*method=*/"basic-card", /*supported_networks_specified=*/false,
+ /*supported_networks=*/{}));
EXPECT_TRUE(GetApp()->IsValidForModifier(
- "basic-card", true, {"unionpay"}, true,
- {autofill::CreditCard::CardType::CARD_TYPE_DEBIT,
- autofill::CreditCard::CardType::CARD_TYPE_CREDIT}));
+ /*method=*/"https://bobpay.com", /*supported_networks_specified=*/true,
+ /*supported_networks=*/{}));
EXPECT_FALSE(GetApp()->IsValidForModifier(
- "basic-card", true, {"unionpay"}, true,
- {autofill::CreditCard::CardType::CARD_TYPE_CREDIT}));
+ /*method=*/"basic-card", /*supported_networks_specified=*/true,
+ /*supported_networks=*/{"mastercard"}));
+
+ EXPECT_TRUE(GetApp()->IsValidForModifier(
+ /*method=*/"basic-card", /*supported_networks_specified=*/true,
+ /*supported_networks=*/{"unionpay"}));
}
} // namespace payments
diff --git a/chromium/components/payments/content/utility/BUILD.gn b/chromium/components/payments/content/utility/BUILD.gn
index f51b14dce88..08e459b07bc 100644
--- a/chromium/components/payments/content/utility/BUILD.gn
+++ b/chromium/components/payments/content/utility/BUILD.gn
@@ -39,9 +39,7 @@ source_set("unit_tests") {
}
fuzzer_test("payment_method_manifest_fuzzer") {
- sources = [
- "payment_method_manifest_parser_fuzzer.cc",
- ]
+ sources = [ "payment_method_manifest_parser_fuzzer.cc" ]
deps = [
":utility",
"//base",
@@ -55,9 +53,7 @@ fuzzer_test("payment_method_manifest_fuzzer") {
}
fuzzer_test("payment_web_app_manifest_fuzzer") {
- sources = [
- "payment_web_app_manifest_parser_fuzzer.cc",
- ]
+ sources = [ "payment_web_app_manifest_parser_fuzzer.cc" ]
deps = [
":utility",
"//base",
@@ -70,9 +66,7 @@ fuzzer_test("payment_web_app_manifest_fuzzer") {
}
fuzzer_test("fingerprint_fuzzer") {
- sources = [
- "fingerprint_parser_fuzzer.cc",
- ]
+ sources = [ "fingerprint_parser_fuzzer.cc" ]
deps = [
":utility",
"//base",
diff --git a/chromium/components/payments/content/utility/payment_manifest_parser.cc b/chromium/components/payments/content/utility/payment_manifest_parser.cc
index bcc3fcb31ff..88719c50034 100644
--- a/chromium/components/payments/content/utility/payment_manifest_parser.cc
+++ b/chromium/components/payments/content/utility/payment_manifest_parser.cc
@@ -68,8 +68,10 @@ const std::string ValidateAndTruncateIfNeeded(const std::string& input,
}
// Parses the "default_applications": ["https://some/url"] from |dict| into
-// |web_app_manifest_urls|. Returns 'false' for invalid data.
-bool ParseDefaultApplications(base::DictionaryValue* dict,
+// |web_app_manifest_urls|. Uses |manifest_url| to resolve relative URLs.
+// Returns 'false' for invalid data.
+bool ParseDefaultApplications(const GURL& manifest_url,
+ base::DictionaryValue* dict,
std::vector<GURL>* web_app_manifest_urls,
const ErrorLogger& log) {
DCHECK(dict);
@@ -77,6 +79,8 @@ bool ParseDefaultApplications(base::DictionaryValue* dict,
base::ListValue* list = nullptr;
if (!dict->GetList(kDefaultApplications, &list)) {
+ // TODO(crbug.com/1065337): Move the error message strings to
+ // components/payments/core/native_error_strings.cc.
log.Error(
base::StringPrintf("\"%s\" must be a list.", kDefaultApplications));
return false;
@@ -92,18 +96,17 @@ bool ParseDefaultApplications(base::DictionaryValue* dict,
for (size_t i = 0; i < apps_number; ++i) {
std::string item;
if (!list->GetString(i, &item) || item.empty() ||
- !base::IsStringUTF8(item) ||
- !(base::StartsWith(item, kHttpsPrefix, base::CompareCase::SENSITIVE) ||
- base::StartsWith(item, kHttpPrefix, base::CompareCase::SENSITIVE))) {
- log.Error(base::StringPrintf(
- "Each entry in \"%s\" must be UTF8 string that starts with \"%s\" or "
- "\"%s\" (for localhost).",
- kDefaultApplications, kHttpsPrefix, kHttpPrefix));
+ !base::IsStringUTF8(item)) {
+ log.Error(base::StringPrintf("Each entry in \"%s\" must be UTF8 string.",
+ kDefaultApplications));
web_app_manifest_urls->clear();
return false;
}
- GURL url(item);
+ GURL url = manifest_url.Resolve(item);
+ // TODO(crbug.com/1065337): Check that |url| is the same origin with
+ // |manifest_url|. Currently that's checked by callers, but the earlier this
+ // is caught, the fewer resources Chrome consumes.
if (!UrlUtil::IsValidManifestUrl(url)) {
const std::string item_to_print =
ValidateAndTruncateIfNeeded(item, nullptr);
@@ -353,6 +356,7 @@ PaymentManifestParser::PaymentManifestParser(std::unique_ptr<ErrorLogger> log)
PaymentManifestParser::~PaymentManifestParser() = default;
void PaymentManifestParser::ParsePaymentMethodManifest(
+ const GURL& manifest_url,
const std::string& content,
PaymentMethodCallback callback) {
parse_payment_callback_counter_++;
@@ -360,7 +364,8 @@ void PaymentManifestParser::ParsePaymentMethodManifest(
data_decoder::DataDecoder::ParseJsonIsolated(
content, base::BindOnce(&PaymentManifestParser::OnPaymentMethodParse,
- weak_factory_.GetWeakPtr(), std::move(callback)));
+ weak_factory_.GetWeakPtr(), manifest_url,
+ std::move(callback)));
}
void PaymentManifestParser::ParseWebAppManifest(const std::string& content,
@@ -384,6 +389,7 @@ void PaymentManifestParser::ParseWebAppInstallationInfo(
// static
void PaymentManifestParser::ParsePaymentMethodManifestIntoVectors(
+ const GURL& manifest_url,
std::unique_ptr<base::Value> value,
const ErrorLogger& log,
std::vector<GURL>* web_app_manifest_urls,
@@ -403,7 +409,8 @@ void PaymentManifestParser::ParsePaymentMethodManifestIntoVectors(
}
if (dict->HasKey(kDefaultApplications) &&
- !ParseDefaultApplications(dict.get(), web_app_manifest_urls, log)) {
+ !ParseDefaultApplications(manifest_url, dict.get(), web_app_manifest_urls,
+ log)) {
return;
}
@@ -555,8 +562,9 @@ bool PaymentManifestParser::ParseWebAppInstallationInfoIntoStructs(
{
base::DictionaryValue* service_worker_dict = nullptr;
if (!dict->GetDictionary(kServiceWorker, &service_worker_dict)) {
- log.Error(
- base::StringPrintf("\"%s\" must be a dictionary", kServiceWorker));
+ log.Error(base::StringPrintf(
+ "\"%s\" must be a dictionary in your web app manifest.",
+ kServiceWorker));
return false;
}
@@ -640,6 +648,7 @@ bool PaymentManifestParser::ParseWebAppInstallationInfoIntoStructs(
}
void PaymentManifestParser::OnPaymentMethodParse(
+ const GURL& manifest_url,
PaymentMethodCallback callback,
data_decoder::DataDecoder::ValueOrError result) {
parse_payment_callback_counter_--;
@@ -650,8 +659,9 @@ void PaymentManifestParser::OnPaymentMethodParse(
if (result.value) {
ParsePaymentMethodManifestIntoVectors(
- base::Value::ToUniquePtrValue(std::move(*result.value)), *log_,
- &web_app_manifest_urls, &supported_origins, &all_origins_supported);
+ manifest_url, base::Value::ToUniquePtrValue(std::move(*result.value)),
+ *log_, &web_app_manifest_urls, &supported_origins,
+ &all_origins_supported);
} else {
log_->Error(*result.error);
}
diff --git a/chromium/components/payments/content/utility/payment_manifest_parser.h b/chromium/components/payments/content/utility/payment_manifest_parser.h
index acf79969d63..a304c94a20a 100644
--- a/chromium/components/payments/content/utility/payment_manifest_parser.h
+++ b/chromium/components/payments/content/utility/payment_manifest_parser.h
@@ -29,14 +29,14 @@ class ErrorLogger;
// Example 1 of valid payment method manifest structure:
//
// {
-// "default_applications": ["https://bobpay.com/payment-app.json"],
+// "default_applications": ["payment-app.json"],
// "supported_origins": ["https://alicepay.com"]
// }
//
// Example 2 of valid payment method manifest structure:
//
// {
-// "default_applications": ["https://bobpay.com/payment-app.json"],
+// "default_applications": ["payment-app.json"],
// "supported_origins": "*"
// }
//
@@ -69,7 +69,9 @@ class ErrorLogger;
// }
//
// Specs:
-// https://docs.google.com/document/d/1izV4uC-tiRJG3JLooqY3YRLU22tYOsLTNq0P_InPJeE
+// https://developers.google.com/web/fundamentals/payments/payment-apps-developer-guide/web-payment-apps
+// https://developers.google.com/web/fundamentals/payments/payment-apps-developer-guide/android-payment-apps
+// https://w3c.github.io/payment-method-manifest/
// https://w3c.github.io/manifest/
//
// Note the JSON parsing is done using the DataDecoder (either OOP or in a safe
@@ -91,6 +93,8 @@ class PaymentManifestParser {
std::string type;
};
+ // TODO(crbug.com/1065337): Return manifest parser errors to caller.
+
// Called on successful parsing of a payment method manifest. Parse failure
// results in empty vectors and "false".
using PaymentMethodCallback = base::OnceCallback<
@@ -109,7 +113,8 @@ class PaymentManifestParser {
explicit PaymentManifestParser(std::unique_ptr<ErrorLogger> log);
~PaymentManifestParser();
- void ParsePaymentMethodManifest(const std::string& content,
+ void ParsePaymentMethodManifest(const GURL& manifest_url,
+ const std::string& content,
PaymentMethodCallback callback);
void ParseWebAppManifest(const std::string& content, WebAppCallback callback);
@@ -122,6 +127,7 @@ class PaymentManifestParser {
// Visible for tests.
static void ParsePaymentMethodManifestIntoVectors(
+ const GURL& manifest_url,
std::unique_ptr<base::Value> value,
const ErrorLogger& log,
std::vector<GURL>* web_app_manifest_urls,
@@ -140,7 +146,8 @@ class PaymentManifestParser {
std::vector<WebAppIcon>* icons);
private:
- void OnPaymentMethodParse(PaymentMethodCallback callback,
+ void OnPaymentMethodParse(const GURL& manifest_url,
+ PaymentMethodCallback callback,
data_decoder::DataDecoder::ValueOrError result);
void OnWebAppParse(WebAppCallback callback,
data_decoder::DataDecoder::ValueOrError result);
diff --git a/chromium/components/payments/content/utility/payment_manifest_parser_unittest.cc b/chromium/components/payments/content/utility/payment_manifest_parser_unittest.cc
index 8b08fe37372..fcda36ad912 100644
--- a/chromium/components/payments/content/utility/payment_manifest_parser_unittest.cc
+++ b/chromium/components/payments/content/utility/payment_manifest_parser_unittest.cc
@@ -24,8 +24,9 @@ void ExpectUnableToParsePaymentMethodManifest(const std::string& input) {
std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(input);
PaymentManifestParser::ParsePaymentMethodManifestIntoVectors(
- std::move(value), ErrorLogger(), &actual_web_app_urls,
- &actual_supported_origins, &actual_all_origins_supported);
+ GURL("https://bobpay.com/pmm.json"), std::move(value), ErrorLogger(),
+ &actual_web_app_urls, &actual_supported_origins,
+ &actual_all_origins_supported);
EXPECT_TRUE(actual_web_app_urls.empty()) << actual_web_app_urls.front();
EXPECT_TRUE(actual_supported_origins.empty())
@@ -45,8 +46,9 @@ void ExpectParsedPaymentMethodManifest(
std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(input);
PaymentManifestParser::ParsePaymentMethodManifestIntoVectors(
- std::move(value), ErrorLogger(), &actual_web_app_urls,
- &actual_supported_origins, &actual_all_origins_supported);
+ GURL("https://bobpay.com/pmm.json"), std::move(value), ErrorLogger(),
+ &actual_web_app_urls, &actual_supported_origins,
+ &actual_all_origins_supported);
EXPECT_EQ(expected_web_app_urls, actual_web_app_urls);
EXPECT_EQ(expected_supported_origins, actual_supported_origins);
@@ -91,9 +93,10 @@ TEST(PaymentManifestParserTest, ListOfEmptyDefaultApplicationsIsMalformed) {
"{\"default_applications\": [\"\"]}");
}
-TEST(PaymentManifestParserTest, RelativeURLDefaultApplicationIsMalformed) {
- ExpectUnableToParsePaymentMethodManifest(
- "{\"default_applications\": [\"manifest.json\"]}");
+TEST(PaymentManifestParserTest, DefaultApplicationCanBeRelativeURL) {
+ ExpectParsedPaymentMethodManifest(
+ "{\"default_applications\": [\"manifest.json\"]}",
+ {GURL("https://bobpay.com/manifest.json")}, {}, false);
}
TEST(PaymentManifestParserTest, DefaultApplicationsShouldNotHaveNulCharacters) {
@@ -111,11 +114,15 @@ TEST(PaymentManifestParserTest, DefaultApplicationKeyShouldBeLowercase) {
"{\"Default_Applications\": [\"https://bobpay.com/app.json\"]}");
}
-TEST(PaymentManifestParserTest, DefaultApplicationsShouldBeAbsoluteUrls) {
- ExpectUnableToParsePaymentMethodManifest(
+TEST(PaymentManifestParserTest,
+ DefaultApplicationsCanBeEitherAbsoluteOrRelative) {
+ ExpectParsedPaymentMethodManifest(
"{\"default_applications\": ["
- "\"https://bobpay.com/app.json\","
- "\"app.json\"]}");
+ "\"https://bobpay.com/app1.json\","
+ "\"app2.json\"]}",
+ {GURL("https://bobpay.com/app1.json"),
+ GURL("https://bobpay.com/app2.json")},
+ {}, false);
}
TEST(PaymentManifestParserTest, DefaultApplicationsShouldBeHttps) {
diff --git a/chromium/components/payments/content/utility/payment_method_manifest_parser_fuzzer.cc b/chromium/components/payments/content/utility/payment_method_manifest_parser_fuzzer.cc
index 266b487524f..6245c7a6ec4 100644
--- a/chromium/components/payments/content/utility/payment_method_manifest_parser_fuzzer.cc
+++ b/chromium/components/payments/content/utility/payment_method_manifest_parser_fuzzer.cc
@@ -39,7 +39,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
payments::ErrorLogger log;
log.DisableInTest();
payments::PaymentManifestParser::ParsePaymentMethodManifestIntoVectors(
- std::move(value), log, &web_app_manifest_urls, &supported_origins,
- &all_origins_supported);
+ GURL("https://chromium.org/pmm.json"), std::move(value), log,
+ &web_app_manifest_urls, &supported_origins, &all_origins_supported);
return 0;
}
diff --git a/chromium/components/payments/core/BUILD.gn b/chromium/components/payments/core/BUILD.gn
index 0f55c095ed4..084d14c4722 100644
--- a/chromium/components/payments/core/BUILD.gn
+++ b/chromium/components/payments/core/BUILD.gn
@@ -12,6 +12,8 @@ jumbo_static_library("core") {
"currency_formatter.h",
"error_logger.cc",
"error_logger.h",
+ "error_message_util.cc",
+ "error_message_util.h",
"features.cc",
"features.h",
"journey_logger.cc",
@@ -38,6 +40,8 @@ jumbo_static_library("core") {
"payment_prefs.h",
"payment_shipping_option.cc",
"payment_shipping_option.h",
+ "payments_experimental_features.cc",
+ "payments_experimental_features.h",
"payments_validators.cc",
"payments_validators.h",
"url_util.cc",
@@ -63,8 +67,6 @@ jumbo_static_library("core") {
"payment_request_delegate.h",
"payment_response.cc",
"payment_response.h",
- "payments_experimental_features.cc",
- "payments_experimental_features.h",
"payments_profile_comparator.cc",
"payments_profile_comparator.h",
"strings_util.cc",
@@ -171,7 +173,6 @@ jumbo_source_set("unit_tests") {
"payment_request_data_util_unittest.cc",
"payment_response_unittest.cc",
"payments_profile_comparator_unittest.cc",
- "strings_util_unittest.cc",
"web_payment_request_unittest.cc",
]
}
@@ -197,99 +198,3 @@ jumbo_source_set("unit_tests") {
"//ui/base",
]
}
-
-if (is_ios) {
- bundle_data("payments_test_bundle_data") {
- testonly = true
-
- sources = [
- "//components/test/data/payments/abort.js",
- "//components/test/data/payments/alicepay_bobpay_charliepay_and_cards.js",
- "//components/test/data/payments/blob_url.js",
- "//components/test/data/payments/bobpay.js",
- "//components/test/data/payments/bobpay_and_basic_card_with_modifier_optional_data.js",
- "//components/test/data/payments/bobpay_and_basic_card_with_modifiers.js",
- "//components/test/data/payments/bobpay_and_cards.js",
- "//components/test/data/payments/bobpay_ui_skip.js",
- "//components/test/data/payments/bobpay_ui_skip_preload.js",
- "//components/test/data/payments/can_make_payment_metrics.js",
- "//components/test/data/payments/can_make_payment_query.js",
- "//components/test/data/payments/can_make_payment_query_bobpay.js",
- "//components/test/data/payments/can_make_payment_query_cc.js",
- "//components/test/data/payments/contact_details.js",
- "//components/test/data/payments/contact_details_and_free_shipping.js",
- "//components/test/data/payments/debit.js",
- "//components/test/data/payments/dynamic_shipping.js",
- "//components/test/data/payments/email.js",
- "//components/test/data/payments/email_and_free_shipping.js",
- "//components/test/data/payments/email_and_phone.js",
- "//components/test/data/payments/extra_shipping_options.js",
- "//components/test/data/payments/fail_complete.js",
- "//components/test/data/payments/free_shipping.js",
- "//components/test/data/payments/initiated.js",
- "//components/test/data/payments/initiated_test.html",
- "//components/test/data/payments/long_id.js",
- "//components/test/data/payments/metrics.js",
- "//components/test/data/payments/modifier.js",
- "//components/test/data/payments/multiple_show.js",
- "//components/test/data/payments/name.js",
- "//components/test/data/payments/name_and_free_shipping.js",
- "//components/test/data/payments/no_shipping.js",
- "//components/test/data/payments/payment_method_identifier.js",
- "//components/test/data/payments/payment_request.html",
- "//components/test/data/payments/payment_request.js",
- "//components/test/data/payments/payment_request_abort_test.html",
- "//components/test/data/payments/payment_request_alicepay_bobpay_charliepay_and_cards_test.html",
- "//components/test/data/payments/payment_request_blob_url_test.html",
- "//components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifier_optional_data_test.html",
- "//components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html",
- "//components/test/data/payments/payment_request_bobpay_and_cards_test.html",
- "//components/test/data/payments/payment_request_bobpay_test.html",
- "//components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html",
- "//components/test/data/payments/payment_request_bobpay_ui_skip_test.html",
- "//components/test/data/payments/payment_request_can_make_payment_metrics_test.html",
- "//components/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html",
- "//components/test/data/payments/payment_request_can_make_payment_query_cc_test.html",
- "//components/test/data/payments/payment_request_can_make_payment_query_test.html",
- "//components/test/data/payments/payment_request_contact_details_and_free_shipping_test.html",
- "//components/test/data/payments/payment_request_contact_details_test.html",
- "//components/test/data/payments/payment_request_debit_test.html",
- "//components/test/data/payments/payment_request_dynamic_shipping_test.html",
- "//components/test/data/payments/payment_request_email_and_free_shipping_test.html",
- "//components/test/data/payments/payment_request_email_and_phone_test.html",
- "//components/test/data/payments/payment_request_email_test.html",
- "//components/test/data/payments/payment_request_extra_shipping_options_test.html",
- "//components/test/data/payments/payment_request_fail_complete_test.html",
- "//components/test/data/payments/payment_request_free_shipping_test.html",
- "//components/test/data/payments/payment_request_id.js",
- "//components/test/data/payments/payment_request_id_test.html",
- "//components/test/data/payments/payment_request_iframe.html",
- "//components/test/data/payments/payment_request_long_id_test.html",
- "//components/test/data/payments/payment_request_main.html",
- "//components/test/data/payments/payment_request_metrics_test.html",
- "//components/test/data/payments/payment_request_modifier_test.html",
- "//components/test/data/payments/payment_request_multiple_requests.html",
- "//components/test/data/payments/payment_request_multiple_show_test.html",
- "//components/test/data/payments/payment_request_name_and_free_shipping_test.html",
- "//components/test/data/payments/payment_request_name_test.html",
- "//components/test/data/payments/payment_request_no_shipping_test.html",
- "//components/test/data/payments/payment_request_payment_method_identifier_test.html",
- "//components/test/data/payments/payment_request_phone_and_free_shipping_test.html",
- "//components/test/data/payments/payment_request_phone_test.html",
- "//components/test/data/payments/payment_request_shipping_address_change_test.html",
- "//components/test/data/payments/payment_request_show_promise.html",
- "//components/test/data/payments/payment_request_show_twice_test.html",
- "//components/test/data/payments/phone.js",
- "//components/test/data/payments/phone_and_free_shipping.js",
- "//components/test/data/payments/shipping_address_change.js",
- "//components/test/data/payments/show_promise.js",
- "//components/test/data/payments/show_twice.js",
- "//components/test/data/payments/style.css",
- "//components/test/data/payments/util.js",
- ]
- outputs = [
- "{{bundle_resources_dir}}/" +
- "{{source_root_relative_dir}}/{{source_file_part}}",
- ]
- }
-}
diff --git a/chromium/components/payments/core/OWNERS b/chromium/components/payments/core/OWNERS
deleted file mode 100644
index a54ecb4e8c0..00000000000
--- a/chromium/components/payments/core/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-per-file journey_logger*=sebsg@chromium.org
-per-file address_normalizer*=sebsg@chromium.org
-
-# COMPONENT: UI>Browser>Payments
diff --git a/chromium/components/payments/core/autofill_payment_app.cc b/chromium/components/payments/core/autofill_payment_app.cc
index 57c34c781a5..72391991696 100644
--- a/chromium/components/payments/core/autofill_payment_app.cc
+++ b/chromium/components/payments/core/autofill_payment_app.cc
@@ -33,7 +33,6 @@ namespace payments {
AutofillPaymentApp::AutofillPaymentApp(
const std::string& method_name,
const autofill::CreditCard& card,
- bool matches_merchant_card_type_exactly,
const std::vector<autofill::AutofillProfile*>& billing_profiles,
const std::string& app_locale,
PaymentRequestBaseDelegate* payment_request_delegate)
@@ -42,7 +41,6 @@ AutofillPaymentApp::AutofillPaymentApp(
PaymentApp::Type::AUTOFILL),
method_name_(method_name),
credit_card_(card),
- matches_merchant_card_type_exactly_(matches_merchant_card_type_exactly),
billing_profiles_(billing_profiles),
app_locale_(app_locale),
delegate_(nullptr),
@@ -95,11 +93,7 @@ uint32_t AutofillPaymentApp::GetCompletenessScore() const {
}
bool AutofillPaymentApp::CanPreselect() const {
- return IsCompleteForPayment() && matches_merchant_card_type_exactly_;
-}
-
-bool AutofillPaymentApp::IsExactlyMatchingMerchantRequest() const {
- return matches_merchant_card_type_exactly_;
+ return IsCompleteForPayment();
}
base::string16 AutofillPaymentApp::GetMissingInfoLabel() const {
@@ -107,7 +101,7 @@ base::string16 AutofillPaymentApp::GetMissingInfoLabel() const {
GetCompletionStatusForCard(credit_card_, app_locale_, billing_profiles_));
}
-bool AutofillPaymentApp::IsValidForCanMakePayment() const {
+bool AutofillPaymentApp::HasEnrolledInstrument() const {
CreditCardCompletionStatus status =
GetCompletionStatusForCard(credit_card_, app_locale_, billing_profiles_);
if (PaymentsExperimentalFeatures::IsEnabled(
@@ -128,6 +122,11 @@ void AutofillPaymentApp::RecordUse() {
credit_card_);
}
+bool AutofillPaymentApp::NeedsInstallation() const {
+ // Autofill payment app is built-in, so it doesn't need installation.
+ return false;
+}
+
base::string16 AutofillPaymentApp::GetLabel() const {
return credit_card_.NetworkAndLastFourDigits();
}
@@ -140,31 +139,12 @@ base::string16 AutofillPaymentApp::GetSublabel() const {
bool AutofillPaymentApp::IsValidForModifier(
const std::string& method,
bool supported_networks_specified,
- const std::set<std::string>& supported_networks,
- bool supported_types_specified,
- const std::set<autofill::CreditCard::CardType>& supported_types) const {
+ const std::set<std::string>& supported_networks) const {
bool is_valid = false;
IsValidForPaymentMethodIdentifier(method, &is_valid);
if (!is_valid)
return false;
- // If supported_types is not specified and this instrument matches the method,
- // the modifier is applicable. If supported_types is populated, it must
- // contain this card's type to be applicable. The same is true for
- // supported_networks.
- if (supported_types_specified) {
- // supported_types may contain CARD_TYPE_UNKNOWN because of the parsing
- // function so the local card only matches if it's because the website
- // didn't specify types (meaning they don't care).
- if (credit_card_.card_type() ==
- autofill::CreditCard::CardType::CARD_TYPE_UNKNOWN) {
- return false;
- }
-
- if (supported_types.find(credit_card_.card_type()) == supported_types.end())
- return false;
- }
-
if (supported_networks_specified) {
std::string basic_card_network =
autofill::data_util::GetPaymentRequestData(credit_card_.network())
@@ -219,18 +199,12 @@ void AutofillPaymentApp::OnFullCardRequestFailed() {
void AutofillPaymentApp::RecordMissingFieldsForApp() const {
CreditCardCompletionStatus completion_status =
GetCompletionStatusForCard(credit_card_, app_locale_, billing_profiles_);
- if (completion_status == CREDIT_CARD_COMPLETE &&
- matches_merchant_card_type_exactly_) {
+ if (completion_status == CREDIT_CARD_COMPLETE)
return;
- }
- // Record cases that the card type does not match the requested type(s) in
- // addititon to missing fields from card completion status.
- base::UmaHistogramSparse(
- "PaymentRequest.MissingPaymentFields",
- completion_status |
- (matches_merchant_card_type_exactly_ ? 0
- : CREDIT_CARD_TYPE_MISMATCH));
+ // Record the missing fields from card completion status.
+ base::UmaHistogramSparse("PaymentRequest.MissingPaymentFields",
+ completion_status);
}
void AutofillPaymentApp::GenerateBasicCardResponse() {
diff --git a/chromium/components/payments/core/autofill_payment_app.h b/chromium/components/payments/core/autofill_payment_app.h
index 365daef0655..c84102570af 100644
--- a/chromium/components/payments/core/autofill_payment_app.h
+++ b/chromium/components/payments/core/autofill_payment_app.h
@@ -32,7 +32,6 @@ class AutofillPaymentApp
AutofillPaymentApp(
const std::string& method_name,
const autofill::CreditCard& card,
- bool matches_merchant_card_type_exactly,
const std::vector<autofill::AutofillProfile*>& billing_profiles,
const std::string& app_locale,
PaymentRequestBaseDelegate* payment_request_delegate);
@@ -43,18 +42,16 @@ class AutofillPaymentApp
bool IsCompleteForPayment() const override;
uint32_t GetCompletenessScore() const override;
bool CanPreselect() const override;
- bool IsExactlyMatchingMerchantRequest() const override;
base::string16 GetMissingInfoLabel() const override;
- bool IsValidForCanMakePayment() const override;
+ bool HasEnrolledInstrument() const override;
void RecordUse() override;
+ bool NeedsInstallation() const override;
base::string16 GetLabel() const override;
base::string16 GetSublabel() const override;
- bool IsValidForModifier(const std::string& method,
- bool supported_networks_specified,
- const std::set<std::string>& supported_networks,
- bool supported_types_specified,
- const std::set<autofill::CreditCard::CardType>&
- supported_types) const override;
+ bool IsValidForModifier(
+ const std::string& method,
+ bool supported_networks_specified,
+ const std::set<std::string>& supported_networks) const override;
base::WeakPtr<PaymentApp> AsWeakPtr() override;
bool HandlesShippingAddress() const override;
bool HandlesPayerName() const override;
@@ -93,12 +90,6 @@ class AutofillPaymentApp
// A copy of the card is owned by this object.
autofill::CreditCard credit_card_;
- // Whether the card type (credit, debit, prepaid) matches the merchant's
- // requested card type exactly. If the merchant accepts all card types, then
- // this variable is always "true". If the merchant accepts only a subset of
- // the card types, then this variable is "false" for unknown card types.
- const bool matches_merchant_card_type_exactly_;
-
// Not owned by this object, should outlive this.
const std::vector<autofill::AutofillProfile*>& billing_profiles_;
diff --git a/chromium/components/payments/core/autofill_payment_app_unittest.cc b/chromium/components/payments/core/autofill_payment_app_unittest.cc
index 4a44c794770..fb69076325b 100644
--- a/chromium/components/payments/core/autofill_payment_app_unittest.cc
+++ b/chromium/components/payments/core/autofill_payment_app_unittest.cc
@@ -155,9 +155,8 @@ class AutofillPaymentAppTest : public testing::Test {
// A valid local credit card is a valid app for payment.
TEST_F(AutofillPaymentAppTest, IsCompleteForPayment) {
- AutofillPaymentApp app("visa", local_credit_card(),
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp app("visa", local_credit_card(), billing_profiles(),
+ "en-US", nullptr);
EXPECT_TRUE(app.IsCompleteForPayment());
EXPECT_TRUE(app.GetMissingInfoLabel().empty());
}
@@ -166,9 +165,7 @@ TEST_F(AutofillPaymentAppTest, IsCompleteForPayment) {
TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_Expired) {
autofill::CreditCard& card = local_credit_card();
card.SetExpirationYear(2016); // Expired.
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
EXPECT_TRUE(app.IsCompleteForPayment());
EXPECT_EQ(base::string16(), app.GetMissingInfoLabel());
}
@@ -179,9 +176,7 @@ TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_NoName) {
card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
base::ASCIIToUTF16(""), "en-US");
base::string16 missing_info;
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
EXPECT_FALSE(app.IsCompleteForPayment());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_NAME_ON_CARD_REQUIRED),
app.GetMissingInfoLabel());
@@ -192,9 +187,7 @@ TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_NoNumber) {
autofill::CreditCard& card = local_credit_card();
card.SetNumber(base::ASCIIToUTF16(""));
base::string16 missing_info;
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
EXPECT_FALSE(app.IsCompleteForPayment());
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE),
@@ -207,9 +200,7 @@ TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_NoBillinbAddressId) {
autofill::CreditCard& card = local_credit_card();
card.set_billing_address_id("");
base::string16 missing_info;
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
EXPECT_FALSE(app.IsCompleteForPayment());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_PAYMENTS_CARD_BILLING_ADDRESS_REQUIRED),
@@ -222,9 +213,7 @@ TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_InvalidBillinbAddressId) {
autofill::CreditCard& card = local_credit_card();
card.set_billing_address_id("InvalidBillingAddressId");
base::string16 missing_info;
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
EXPECT_FALSE(app.IsCompleteForPayment());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_PAYMENTS_CARD_BILLING_ADDRESS_REQUIRED),
@@ -240,9 +229,7 @@ TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_IncompleteBillinbAddress) {
autofill::CreditCard& card = local_credit_card();
card.set_billing_address_id(incomplete_profile.guid());
base::string16 missing_info;
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
EXPECT_FALSE(app.IsCompleteForPayment());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_PAYMENTS_CARD_BILLING_ADDRESS_REQUIRED),
@@ -256,9 +243,7 @@ TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_MultipleThingsMissing) {
card.SetNumber(base::ASCIIToUTF16(""));
card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
base::ASCIIToUTF16(""), "en-US");
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
EXPECT_FALSE(app.IsCompleteForPayment());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_MORE_INFORMATION_REQUIRED),
app.GetMissingInfoLabel());
@@ -269,9 +254,7 @@ TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_MaskedCard) {
autofill::CreditCard card = autofill::test::GetMaskedServerCard();
ASSERT_GT(billing_profiles().size(), 0UL);
card.set_billing_address_id(billing_profiles()[0]->guid());
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
EXPECT_TRUE(app.IsCompleteForPayment());
EXPECT_TRUE(app.GetMissingInfoLabel().empty());
}
@@ -282,52 +265,42 @@ TEST_F(AutofillPaymentAppTest, IsCompleteForPayment_ExpiredMaskedCard) {
ASSERT_GT(billing_profiles().size(), 0UL);
card.set_billing_address_id(billing_profiles()[0]->guid());
card.SetExpirationYear(2016); // Expired.
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
EXPECT_TRUE(app.IsCompleteForPayment());
EXPECT_EQ(base::string16(), app.GetMissingInfoLabel());
}
// An expired card is a valid app for canMakePayment.
-TEST_F(AutofillPaymentAppTest, IsValidForCanMakePayment_Minimal) {
+TEST_F(AutofillPaymentAppTest, HasEnrolledInstrument_Minimal) {
autofill::CreditCard& card = local_credit_card();
card.SetExpirationYear(2016); // Expired.
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
- EXPECT_TRUE(app.IsValidForCanMakePayment());
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
+ EXPECT_TRUE(app.HasEnrolledInstrument());
}
// An expired Masked (server) card is a valid app for canMakePayment.
-TEST_F(AutofillPaymentAppTest, IsValidForCanMakePayment_MaskedCard) {
+TEST_F(AutofillPaymentAppTest, HasEnrolledInstrument_MaskedCard) {
autofill::CreditCard card = autofill::test::GetMaskedServerCard();
card.SetExpirationYear(2016); // Expired.
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
- EXPECT_TRUE(app.IsValidForCanMakePayment());
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
+ EXPECT_TRUE(app.HasEnrolledInstrument());
}
// A card with no name is not a valid app for canMakePayment.
-TEST_F(AutofillPaymentAppTest, IsValidForCanMakePayment_NoName) {
+TEST_F(AutofillPaymentAppTest, HasEnrolledInstrument_NoName) {
autofill::CreditCard& card = local_credit_card();
card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
base::ASCIIToUTF16(""), "en-US");
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
- EXPECT_FALSE(app.IsValidForCanMakePayment());
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
+ EXPECT_FALSE(app.HasEnrolledInstrument());
}
// A card with no number is not a valid app for canMakePayment.
-TEST_F(AutofillPaymentAppTest, IsValidForCanMakePayment_NoNumber) {
+TEST_F(AutofillPaymentAppTest, HasEnrolledInstrument_NoNumber) {
autofill::CreditCard& card = local_credit_card();
card.SetNumber(base::ASCIIToUTF16(""));
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", nullptr);
- EXPECT_FALSE(app.IsValidForCanMakePayment());
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", nullptr);
+ EXPECT_FALSE(app.HasEnrolledInstrument());
}
// Tests that the autofill app only calls OnappDetailsReady when
@@ -341,9 +314,7 @@ TEST_F(AutofillPaymentAppTest, InvokePaymentApp_NormalizationBeforeUnmask) {
autofill::CreditCard& card = local_credit_card();
card.SetNumber(base::ASCIIToUTF16(""));
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", &delegate);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", &delegate);
FakePaymentAppDelegate app_delegate;
@@ -371,9 +342,7 @@ TEST_F(AutofillPaymentAppTest, InvokePaymentApp_UnmaskBeforeNormalization) {
autofill::CreditCard& card = local_credit_card();
card.SetNumber(base::ASCIIToUTF16(""));
- AutofillPaymentApp app("visa", card,
- /*matches_merchant_card_type_exactly=*/true,
- billing_profiles(), "en-US", &delegate);
+ AutofillPaymentApp app("visa", card, billing_profiles(), "en-US", &delegate);
FakePaymentAppDelegate app_delegate;
diff --git a/chromium/components/payments/core/error_message_util.cc b/chromium/components/payments/core/error_message_util.cc
new file mode 100644
index 00000000000..0bd30d292a1
--- /dev/null
+++ b/chromium/components/payments/core/error_message_util.cc
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/payments/core/error_message_util.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "components/payments/core/native_error_strings.h"
+
+namespace payments {
+
+std::string GetNotSupportedErrorMessage(const std::set<std::string>& methods) {
+ if (methods.empty())
+ return errors::kGenericPaymentMethodNotSupportedMessage;
+
+ std::vector<std::string> with_quotes(methods.size());
+ std::transform(
+ methods.begin(), methods.end(), with_quotes.begin(),
+ [](const std::string& method_name) { return "\"" + method_name + "\""; });
+
+ std::string output;
+ bool replaced = base::ReplaceChars(
+ with_quotes.size() == 1
+ ? errors::kSinglePaymentMethodNotSupportedFormat
+ : errors::kMultiplePaymentMethodsNotSupportedFormat,
+ "$", base::JoinString(with_quotes, ", "), &output);
+ DCHECK(replaced);
+ return output;
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/core/error_message_util.h b/chromium/components/payments/core/error_message_util.h
new file mode 100644
index 00000000000..a99870480a9
--- /dev/null
+++ b/chromium/components/payments/core/error_message_util.h
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PAYMENTS_CORE_ERROR_MESSAGE_UTIL_H_
+#define COMPONENTS_PAYMENTS_CORE_ERROR_MESSAGE_UTIL_H_
+
+#include <set>
+#include <string>
+
+namespace payments {
+
+// Returns a developer-facing error message that the given payment |methods| are
+// not supported.
+std::string GetNotSupportedErrorMessage(const std::set<std::string>& methods);
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CORE_ERROR_MESSAGE_UTIL_H_
diff --git a/chromium/components/payments/core/error_strings.cc b/chromium/components/payments/core/error_strings.cc
index a411d7ad739..ccf6dfa96d0 100644
--- a/chromium/components/payments/core/error_strings.cc
+++ b/chromium/components/payments/core/error_strings.cc
@@ -17,7 +17,6 @@ const char kCannotShowTwice[] = "Attempted show twice.";
const char kCannotShowWithoutInit[] = "Attempted show without initialization.";
const char kCannotUpdateWithoutInit[] = "Attempted updateWith without initialization.";
const char kCannotUpdateWithoutShow[] = "Attempted updateWith without show.";
-const char kGenericPaymentMethodNotSupportedMessage[] = "Payment method not supported.";
const char kInvalidState[] = "Invalid state.";
const char kNotInASecureOrigin[] = "Not in a secure origin.";
const char kProhibitedOrigin[] = "Only localhost, file://, and cryptographic scheme origins allowed.";
diff --git a/chromium/components/payments/core/error_strings.h b/chromium/components/payments/core/error_strings.h
index ced992e0b56..7187e4d8b7b 100644
--- a/chromium/components/payments/core/error_strings.h
+++ b/chromium/components/payments/core/error_strings.h
@@ -35,9 +35,6 @@ extern const char kCannotUpdateWithoutInit[];
// Mojo call PaymentRequest::Show() must precede PaymentRequest::UpdateWith().
extern const char kCannotUpdateWithoutShow[];
-// A message about unsupported payment method.
-extern const char kGenericPaymentMethodNotSupportedMessage[];
-
// Used when an invalid state is encountered generically.
extern const char kInvalidState[];
diff --git a/chromium/components/payments/core/features.cc b/chromium/components/payments/core/features.cc
index 865507a2b0e..684aaa8bea7 100644
--- a/chromium/components/payments/core/features.cc
+++ b/chromium/components/payments/core/features.cc
@@ -53,8 +53,8 @@ const base::Feature kPaymentRequestSkipToGPay{
const base::Feature kPaymentRequestSkipToGPayIfNoCard{
"PaymentRequestSkipToGPayIfNoCard", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kWebPaymentMicrotransaction{
- "WebPaymentMicrotransaction", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kDownRankJustInTimePaymentApp{
+ "DownRankJustInTimePaymentApp", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
} // namespace payments
diff --git a/chromium/components/payments/core/features.h b/chromium/components/payments/core/features.h
index 8cdade4a77b..4b492b143ff 100644
--- a/chromium/components/payments/core/features.h
+++ b/chromium/components/payments/core/features.h
@@ -60,8 +60,9 @@ extern const base::Feature kPaymentRequestSkipToGPay;
// eligible credit card.
extern const base::Feature kPaymentRequestSkipToGPayIfNoCard;
-// Controls whether the microtransaction features are enabled.
-extern const base::Feature kWebPaymentMicrotransaction;
+// If enabled, just-in-time installable payment handlers are ranked lower than
+// complete autofill instruments in payment sheet's method selection section.
+extern const base::Feature kDownRankJustInTimePaymentApp;
} // namespace features
} // namespace payments
diff --git a/chromium/components/payments/core/journey_logger.cc b/chromium/components/payments/core/journey_logger.cc
index 572d4886af8..92e7b958cff 100644
--- a/chromium/components/payments/core/journey_logger.cc
+++ b/chromium/components/payments/core/journey_logger.cc
@@ -80,19 +80,13 @@ void RecordTimeToCheckoutUmaHistograms(const std::string name,
base::TimeDelta::FromMinutes(5) /* max */, 100 /*bucket count*/);
}
-enum class TransactionSize {
- kZeroTransaction = 0,
- kMicroTransaction = 1,
- kRegularTransaction = 2,
- kMaxValue = kRegularTransaction,
-};
-
} // namespace
-JourneyLogger::JourneyLogger(bool is_incognito, ukm::SourceId source_id)
+JourneyLogger::JourneyLogger(bool is_incognito,
+ ukm::SourceId payment_request_source_id)
: is_incognito_(is_incognito),
events_(EVENT_INITIATED),
- source_id_(source_id) {}
+ payment_request_source_id_(payment_request_source_id) {}
JourneyLogger::~JourneyLogger() {
// has_recorded_ is false in cases that the page gets closed. To see more
@@ -259,6 +253,15 @@ void JourneyLogger::RecordTransactionAmount(std::string currency,
transaction_size = TransactionSize::kMicroTransaction;
base::UmaHistogramEnumeration(
"PaymentRequest.TransactionAmount" + completion_suffix, transaction_size);
+
+ if (payment_request_source_id_ == ukm::kInvalidSourceId)
+ return;
+
+ // Record the transaction amount in UKM.
+ ukm::builders::PaymentRequest_TransactionAmount(payment_request_source_id_)
+ .SetCompletionStatus(completed)
+ .SetCategory(static_cast<int64_t>(transaction_size))
+ .Record(ukm::UkmRecorder::Get());
}
void JourneyLogger::RecordJourneyStatsHistograms(
@@ -351,14 +354,26 @@ void JourneyLogger::RecordEventsMetric(CompletionStatus completion_status) {
ValidateEventBits();
base::UmaHistogramSparse("PaymentRequest.Events", events_);
- if (source_id_ == ukm::kInvalidSourceId)
+ if (payment_request_source_id_ == ukm::kInvalidSourceId)
return;
// Record the events in UKM.
- ukm::builders::PaymentRequest_CheckoutEvents(source_id_)
+ ukm::builders::PaymentRequest_CheckoutEvents(payment_request_source_id_)
+ .SetCompletionStatus(completion_status)
+ .SetEvents(events_)
+ .Record(ukm::UkmRecorder::Get());
+
+ if (payment_app_source_id_ == ukm::kInvalidSourceId)
+ return;
+
+ // Record the events in UKM for payment app.
+ ukm::builders::PaymentApp_CheckoutEvents(payment_app_source_id_)
.SetCompletionStatus(completion_status)
.SetEvents(events_)
.Record(ukm::UkmRecorder::Get());
+
+ // Clear payment app source id since it gets deleted after recording.
+ payment_app_source_id_ = ukm::kInvalidSourceId;
}
void JourneyLogger::RecordTimeToCheckout(
@@ -488,4 +503,9 @@ void JourneyLogger::SetTriggerTime() {
trigger_time_ = base::TimeTicks::Now();
}
+void JourneyLogger::SetPaymentAppUkmSourceId(
+ ukm::SourceId payment_app_source_id) {
+ payment_app_source_id_ = payment_app_source_id;
+}
+
} // namespace payments
diff --git a/chromium/components/payments/core/journey_logger.h b/chromium/components/payments/core/journey_logger.h
index 02f8d941ec7..47cf99c4d0c 100644
--- a/chromium/components/payments/core/journey_logger.h
+++ b/chromium/components/payments/core/journey_logger.h
@@ -140,7 +140,19 @@ class JourneyLogger {
NOT_SHOWN_REASON_MAX = 4,
};
- JourneyLogger(bool is_incognito, ukm::SourceId source_id);
+ // Transactions fall in one of the following categories after converting to
+ // USD.
+ enum class TransactionSize {
+ // 0$ transactions.
+ kZeroTransaction = 0,
+ // Transaction value <= 1$.
+ kMicroTransaction = 1,
+ // Transaction value > 1$.
+ kRegularTransaction = 2,
+ kMaxValue = kRegularTransaction,
+ };
+
+ JourneyLogger(bool is_incognito, ukm::SourceId payment_request_source_id);
~JourneyLogger();
// Increments the number of selection adds for the specified section.
@@ -203,6 +215,9 @@ class JourneyLogger {
// Records when Payment Request .show is called.
void SetTriggerTime();
+ // Sets the ukm source id of the selected app when it gets invoked.
+ void SetPaymentAppUkmSourceId(ukm::SourceId payment_app_source_id);
+
private:
static const int NUMBER_OF_SECTIONS = 3;
@@ -273,7 +288,8 @@ class JourneyLogger {
// checkout duration.
base::TimeTicks trigger_time_;
- ukm::SourceId source_id_;
+ ukm::SourceId payment_request_source_id_;
+ ukm::SourceId payment_app_source_id_ = ukm::kInvalidSourceId;
DISALLOW_COPY_AND_ASSIGN(JourneyLogger);
};
diff --git a/chromium/components/payments/core/method_strings.cc b/chromium/components/payments/core/method_strings.cc
index 38d0b9e1e5f..177d810616c 100644
--- a/chromium/components/payments/core/method_strings.cc
+++ b/chromium/components/payments/core/method_strings.cc
@@ -14,6 +14,7 @@ namespace methods {
const char kAndroidPay[] = "https://android.com/pay";
const char kBasicCard[] = "basic-card";
const char kGooglePay[] = "https://google.com/pay";
+const char kGooglePlayBilling[] = "https://play.google.com/billing";
const char kInterledger[] = "interledger";
const char kPayeeCreditTransfer[] = "payee-credit-transfer";
const char kPayerCreditTransfer[] = "payer-credit-transfer";
diff --git a/chromium/components/payments/core/method_strings.h b/chromium/components/payments/core/method_strings.h
index a16179808be..25f97e8b6cb 100644
--- a/chromium/components/payments/core/method_strings.h
+++ b/chromium/components/payments/core/method_strings.h
@@ -25,6 +25,9 @@ extern const char kBasicCard[];
// https://developers.google.com/pay/api/web/guides/tutorial
extern const char kGooglePay[];
+// Google Play Billing method name.
+extern const char kGooglePlayBilling[];
+
// Interledger method name.
// https://w3c.github.io/webpayments/proposals/interledger/
extern const char kInterledger[];
diff --git a/chromium/components/payments/core/native_error_strings.cc b/chromium/components/payments/core/native_error_strings.cc
index bc579579735..d45bad6fc3b 100644
--- a/chromium/components/payments/core/native_error_strings.cc
+++ b/chromium/components/payments/core/native_error_strings.cc
@@ -53,9 +53,6 @@ const char kCrossOriginWebAppManifestNotAllowed[] =
const char kDetailedInvalidSslCertificateMessageFormat[] =
"SSL certificate is not valid. Security level: $.";
-const char kHttpHeadRequestFailed[] =
- "Unable to make a HEAD request to \"$1\" for payment method manifest.";
-
const char kHttpStatusCodeNotAllowed[] =
"HTTP status code $1 \"$2\" not allowed for payment method manifest "
"\"$3\".";
@@ -64,6 +61,9 @@ const char kInstallingMultipleDefaultAppsNotSupported[] =
"Installing multiple payment handlers from a single payment method "
"manifest is not supported.";
+const char kInvalidInitiatorFrame[] =
+ "Cannot initialize PaymentRequest in an invalid frame.";
+
const char kInvalidManifestUrl[] =
"\"$1\" is not a valid payment manifest URL with HTTPS scheme (or HTTP "
"scheme for localhost).";
@@ -76,6 +76,10 @@ const char kInvalidServiceWorkerUrl[] =
const char kInvalidSslCertificate[] = "SSL certificate is not valid.";
+const char kInvalidWebAppIcon[] =
+ "Failed to download or decode a non-empty icon for payment app with \"$1\" "
+ "manifest.";
+
const char kMethodDataRequired[] = "Method data required.";
const char kMethodNameRequired[] = "Method name required.";
@@ -89,9 +93,6 @@ const char kMissingMethodNameFromPaymentApp[] =
const char kMultiplePaymentMethodsNotSupportedFormat[] =
"The payment methods $ are not supported.";
-const char kNoLinkRelPaymentMethodManifestHttpHeader[] =
- "No \"Link: rel=payment-method-manifest\" HTTP header found at \"$1\".";
-
const char kNoResponseToPaymentEvent[] =
"Payment handler did not respond to \"paymentrequest\" event.";
@@ -163,5 +164,69 @@ const char kShippingAddressInvalid[] =
const char kShippingOptionEmpty[] =
"Payment app returned invalid response. Missing field \"shipping option\".";
+const char kCanMakePaymentEventRejected[] =
+ "Payment handler rejected the promise passed into "
+ "CanMakePaymentEvent.respondWith().";
+
+const char kCanMakePaymentEventTimeout[] =
+ "The \"canmakepayment\" event timed out.";
+
+const char kCanMakePaymentEventNoResponse[] =
+ "Payment handler did not respond to \"canmakepayment\" event.";
+
+const char kCanMakePaymentEventNoReadyForMinimalUiValue[] =
+ "Payment handler did not specify a value for \"readyForMinimalUI\" in "
+ "CanMakePaymentEvent.respondWithMinimalUI()..";
+
+const char kCanMakePaymentEventBooleanConversionError[] =
+ "Unable to convert the value of \"canmakepayment\" response to a boolean.";
+
+const char kCanMakePaymentEventBrowserError[] =
+ "Browser encountered an error when firing the \"canmakepayment\" event in "
+ "the payment handler.";
+
+const char kCanMakePaymentEventInternalError[] =
+ "Payment handler encountered an error (e.g., threw a JavaScript exception) "
+ "while responding to \"canmakepayment\" event.";
+
+const char kCanMakePaymentEventInvalidAccountBalanceValue[] =
+ "Payment handler provided invalid account balance value in "
+ "CanMakePaymentEvent.respondWithMinimalUI().";
+
+const char kCanMakePaymentEventMinimalUiResponseConversionError[] =
+ "Unable to parse the object that the payment handler passed into "
+ "CanMakePaymentEvent.respondWithMinimalUI().";
+
+const char kCanMakePaymentEventNoAccountBalanceValue[] =
+ "Payment handler did not specify account balance in "
+ "CanMakePaymentEvent.respondWithMinimalUI().";
+
+const char kCanMakePaymentEventNoCanMakePaymentValue[] =
+ "Payment handler did not specify a value for \"canMakePayment\" in "
+ "CanMakePaymentEvent.respondWithMinimalUI().";
+
+const char kCanMakePaymentEventNoUrlBasedPaymentMethods[] =
+ "Browser did not fire \"canmakepayment\" event because the payment handler "
+ "does not support any URL-based payment methods.";
+
+const char kCanMakePaymentEventNotInstalled[] =
+ "Browser did not fire \"canmakepayment\" event because the payment handler "
+ "is not yet installed. It will be installed on demand when the user "
+ "selects it.";
+
+const char kCanMakePaymentEventNoExplicitlyVerifiedMethods[] =
+ "Browser did not fire \"canmakepayment\" event because the payment handler "
+ "does not support any explicitly verified payment methods.";
+
+const char kGenericPaymentMethodNotSupportedMessage[] =
+ "Payment method not supported.";
+
+const char kNoContentAndNoLinkHeader[] =
+ "No content and no \"Link: rel=payment-method-manifest\" HTTP header found "
+ "at \"$1\".";
+
+const char kNoContentInPaymentManifest[] =
+ "No content found in payment manifest \"$1\".";
+
} // namespace errors
} // namespace payments
diff --git a/chromium/components/payments/core/native_error_strings.h b/chromium/components/payments/core/native_error_strings.h
index fb234c3439d..f723ff4338b 100644
--- a/chromium/components/payments/core/native_error_strings.h
+++ b/chromium/components/payments/core/native_error_strings.h
@@ -71,10 +71,6 @@ extern const char kCrossOriginWebAppManifestNotAllowed[];
// to replace.
extern const char kDetailedInvalidSslCertificateMessageFormat[];
-// Used when a HEAD request for URL A fails. This format should be used with
-// base::ReplaceStringPlaceholders(fmt, {A}, nullptr).
-extern const char kHttpHeadRequestFailed[];
-
// Used for HTTP redirects that are prohibited for payment method manifests.
// This format should be used with base::ReplaceStringPlaceholders(fmt,
// {http_code, http_code_phrase, original_url}, nullptr).
@@ -84,6 +80,10 @@ extern const char kHttpStatusCodeNotAllowed[];
// install feature to work.
extern const char kInstallingMultipleDefaultAppsNotSupported[];
+// PaymentRequest::Init() is called when the initiating RenderFrameHost no
+// longer exists.
+extern const char kInvalidInitiatorFrame[];
+
// Used to let the web developer know about an invalid payment manifest URL A.
// This format should be used with base::ReplaceStringPlaceholders(fmt, {A},
// nullptr).
@@ -99,6 +99,10 @@ extern const char kInvalidServiceWorkerUrl[];
// invalid SSL certificate.
extern const char kInvalidSslCertificate[];
+// The downloaded web app icon should draw something for JIT install feature to
+// work.
+extern const char kInvalidWebAppIcon[];
+
// Used when the {"supportedMethods": "", data: {}} is required, but not
// provided.
extern const char kMethodDataRequired[];
@@ -117,11 +121,6 @@ extern const char kMissingMethodNameFromPaymentApp[];
// where "$" is the character to replace.
extern const char kMultiplePaymentMethodsNotSupportedFormat[];
-// Used when the payment method URL A does not have a "Link:
-// rel=payment-method-manifest" HTTP header. This format should be used with
-// base::ReplaceStringPlaceholders(fmt, {A}, nullptr).
-extern const char kNoLinkRelPaymentMethodManifestHttpHeader[];
-
// Payment handler did not respond to the "paymentrequest" event.
extern const char kNoResponseToPaymentEvent[];
@@ -196,6 +195,68 @@ extern const char kShippingAddressInvalid[];
// The payment handler responded with an empty "shipping option" field.
extern const char kShippingOptionEmpty[];
+// The payment handler rejected the promise passed into
+// CanMakePaymentEvent.respondWith().
+extern const char kCanMakePaymentEventRejected[];
+
+// The payment handler timed out responding to "canmakepayment" event.
+extern const char kCanMakePaymentEventTimeout[];
+
+// The payment handler did not respond to the "canmakepayment" event.
+extern const char kCanMakePaymentEventNoResponse[];
+
+// The payment handler did not specify a value for "readyForMinimalUI" field.
+extern const char kCanMakePaymentEventNoReadyForMinimalUiValue[];
+
+// The payment handler called CanMakePaymentEvent.respondWith(value) with a
+// non-boolean value.
+extern const char kCanMakePaymentEventBooleanConversionError[];
+
+// Browser encountered an error when firing the "canmakepayment" event.
+extern const char kCanMakePaymentEventBrowserError[];
+
+// The payment handler threw a JavaScript exception while handling the
+// "canmakepayment" event.
+extern const char kCanMakePaymentEventInternalError[];
+
+// The payment handler specified an invalid value for "accountBalance".
+extern const char kCanMakePaymentEventInvalidAccountBalanceValue[];
+
+// The payment handler called CanMakePaymentEvent.respondWithMinimalUI(value)
+// with a value that could not be converted into a JavaScript dictionary with
+// values for "canMakePayment", "readyForMinimalUI", and "accountBalance".
+extern const char kCanMakePaymentEventMinimalUiResponseConversionError[];
+
+// The payment handler did not specify a value for "accountBalance".
+extern const char kCanMakePaymentEventNoAccountBalanceValue[];
+
+// The payment handler did not specify a value for "canMakePayment" field in
+// CanMakePaymentEvent.respondWithMinimalUI().
+extern const char kCanMakePaymentEventNoCanMakePaymentValue[];
+
+// Browser does not fire the "canmakepayment" event if the payment handler does
+// not support any URL-based payment methods.
+extern const char kCanMakePaymentEventNoUrlBasedPaymentMethods[];
+
+// Browser does not fire the "canmakepayment" event for just-in-time installable
+// payment handlers.
+extern const char kCanMakePaymentEventNotInstalled[];
+
+// Browser fires the "canmakepayment" event only for explicitly verified payment
+// methods, i.e., not when "supportedOrigins": "*".
+extern const char kCanMakePaymentEventNoExplicitlyVerifiedMethods[];
+
+// A message about unsupported payment method.
+extern const char kGenericPaymentMethodNotSupportedMessage[];
+
+// Used for errors downloading the payment method manifest. This format should
+// be used with base::ReplaceStringPlaceholders(fmt, {A}, nullptr).
+extern const char kNoContentAndNoLinkHeader[];
+
+// User when the downloaded payment manifest A is empty. This format should be
+// used with base::ReplaceStringPlaceholders(fmt, {A}, nullptr).
+extern const char kNoContentInPaymentManifest[];
+
} // namespace errors
} // namespace payments
diff --git a/chromium/components/payments/core/payment_app.cc b/chromium/components/payments/core/payment_app.cc
index f0a162ddcfe..6cfe02e7225 100644
--- a/chromium/components/payments/core/payment_app.cc
+++ b/chromium/components/payments/core/payment_app.cc
@@ -8,8 +8,40 @@
#include "components/autofill/core/common/autofill_clock.h"
#include "components/payments/core/autofill_payment_app.h"
+#include "components/payments/core/features.h"
+#include "components/payments/core/payments_experimental_features.h"
namespace payments {
+namespace {
+
+// Returns the sorting group of a payment app. This is used to order payment
+// apps in the order of:
+// 1. Installed 3rd-party payment handlers
+// 2. Complete autofill instruments
+// 3. Just-in-time installable payment handlers that is not yet installed.
+// 4. Incomplete autofill instruments
+int GetSortingGroup(const PaymentApp& app) {
+ switch (app.type()) {
+ case PaymentApp::Type::SERVICE_WORKER_APP:
+ case PaymentApp::Type::NATIVE_MOBILE_APP:
+ // If the experimental feature is enabled, sort 3rd-party payment handlers
+ // that needs installation below autofill instruments.
+ if (app.NeedsInstallation() &&
+ PaymentsExperimentalFeatures::IsEnabled(
+ features::kDownRankJustInTimePaymentApp)) {
+ return 3;
+ }
+ return 1;
+ break;
+ case PaymentApp::Type::AUTOFILL:
+ if (app.IsCompleteForPayment()) {
+ return 2;
+ } else {
+ return 4;
+ }
+ }
+}
+} // namespace
PaymentApp::PaymentApp(int icon_resource_id, Type type)
: icon_resource_id_(icon_resource_id), type_(type) {}
@@ -30,6 +62,10 @@ const std::set<std::string>& PaymentApp::GetAppMethodNames() const {
return app_method_names_;
}
+ukm::SourceId PaymentApp::UkmSourceId() {
+ return ukm::kInvalidSourceId;
+}
+
// static
void PaymentApp::SortApps(std::vector<std::unique_ptr<PaymentApp>>* apps) {
DCHECK(apps);
@@ -47,25 +83,21 @@ void PaymentApp::SortApps(std::vector<PaymentApp*>* apps) {
}
bool PaymentApp::operator<(const PaymentApp& other) const {
- // Non-autofill apps before autofill.
- if (type_ == Type::AUTOFILL && other.type() != Type::AUTOFILL)
- return false;
- if (type_ != Type::AUTOFILL && other.type() == Type::AUTOFILL)
- return true;
+ int sorting_group = GetSortingGroup(*this);
+ int other_sorting_group = GetSortingGroup(other);
+ // First sort payment apps by their sorting group.
+ if (sorting_group != other_sorting_group) {
+ return sorting_group < other_sorting_group;
+ }
+
+ // Within a group, compare by completeness.
// Non-autofill apps have max completeness score. Autofill cards are sorted
// based on completeness. (Each autofill card is considered an app.)
int completeness = GetCompletenessScore() - other.GetCompletenessScore();
if (completeness != 0)
return completeness > 0;
- // Among equally complete cards, those with matching type come before unknown
- // type cards.
- if (IsExactlyMatchingMerchantRequest() !=
- other.IsExactlyMatchingMerchantRequest()) {
- return IsExactlyMatchingMerchantRequest();
- }
-
// Sort autofill cards using their frecency scores as tie breaker.
if (type_ == Type::AUTOFILL) {
DCHECK_EQ(other.type(), Type::AUTOFILL);
diff --git a/chromium/components/payments/core/payment_app.h b/chromium/components/payments/core/payment_app.h
index e4563d85a32..5cf771dce2a 100644
--- a/chromium/components/payments/core/payment_app.h
+++ b/chromium/components/payments/core/payment_app.h
@@ -15,6 +15,7 @@
#include "build/build_config.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/payments/core/payer_data.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "ui/gfx/image/image_skia.h"
namespace payments {
@@ -57,19 +58,15 @@ class PaymentApp {
// the apps can be preselected, the user must explicitly select an app from a
// list.
virtual bool CanPreselect() const = 0;
- // Returns whether the app is exactly matching all filters provided by the
- // merchant. For example, this can return "false" for unknown autofill card
- // types, if the merchant requested only debit cards from "basic-card".
- virtual bool IsExactlyMatchingMerchantRequest() const = 0;
// Returns a message to indicate to the user what's missing for the app to be
// complete for payment.
virtual base::string16 GetMissingInfoLabel() const = 0;
- // Returns whether the app is valid for the purposes of responding to
- // canMakePayment.
- // TODO(crbug.com/915907): rename to IsValidForHasEnrolledInstrument.
- virtual bool IsValidForCanMakePayment() const = 0;
+ // Returns this app's answer for PaymentRequest.hasEnrolledInstrument().
+ virtual bool HasEnrolledInstrument() const = 0;
// Records the use of this payment app.
virtual void RecordUse() = 0;
+ // Check whether this payment app needs installation before it can be used.
+ virtual bool NeedsInstallation() const = 0;
// Return the sub/label of payment app, to be displayed to the user.
virtual base::string16 GetLabel() const = 0;
virtual base::string16 GetSublabel() const = 0;
@@ -77,16 +74,13 @@ class PaymentApp {
// Returns true if this payment app can be used to fulfill a request
// specifying |method| as supported method of payment. The parsed basic-card
- // specific data (supported_networks, supported_types, etc) is relevant only
- // for the AutofillPaymentApp, which runs inside of the browser process and
- // thus should not be parsing untrusted JSON strings from the renderer.
+ // specific data (supported_networks) is relevant only for the
+ // AutofillPaymentApp, which runs inside of the browser process and thus
+ // should not be parsing untrusted JSON strings from the renderer.
virtual bool IsValidForModifier(
const std::string& method,
bool supported_networks_specified,
- const std::set<std::string>& supported_networks,
- bool supported_types_specified,
- const std::set<autofill::CreditCard::CardType>& supported_types)
- const = 0;
+ const std::set<std::string>& supported_networks) const = 0;
// Sets |is_valid| to true if this payment app can handle payments for the
// given |payment_method_identifier|. The |is_valid| is an out-param instead
@@ -117,6 +111,8 @@ class PaymentApp {
int icon_resource_id() const { return icon_resource_id_; }
Type type() const { return type_; }
+ virtual ukm::SourceId UkmSourceId();
+
protected:
PaymentApp(int icon_resource_id, Type type);
diff --git a/chromium/components/payments/core/payment_manifest_downloader.cc b/chromium/components/payments/core/payment_manifest_downloader.cc
index 21d9d82eb9a..b1728535284 100644
--- a/chromium/components/payments/core/payment_manifest_downloader.cc
+++ b/chromium/components/payments/core/payment_manifest_downloader.cc
@@ -12,6 +12,7 @@
#include "base/optional.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/link_header_util/link_header_util.h"
@@ -33,59 +34,29 @@
namespace payments {
namespace {
-GURL ParseResponseHeader(const GURL& url,
- scoped_refptr<net::HttpResponseHeaders> headers,
- const ErrorLogger& log,
- std::string* out_error_message) {
- if (!headers) {
- *out_error_message = base::ReplaceStringPlaceholders(
- errors::kNoLinkRelPaymentMethodManifestHttpHeader, {url.spec()},
- nullptr);
- log.Error(*out_error_message);
- return GURL();
- }
-
- int response_code = headers->response_code();
- if (response_code != net::HTTP_OK && response_code != net::HTTP_NO_CONTENT) {
- *out_error_message = base::ReplaceStringPlaceholders(
- errors::kHttpHeadRequestFailed, {url.spec()}, nullptr),
- log.Error(*out_error_message);
- return GURL();
- }
-
- std::string link_header;
- headers->GetNormalizedHeader("link", &link_header);
- if (link_header.empty()) {
- *out_error_message = base::ReplaceStringPlaceholders(
- errors::kNoLinkRelPaymentMethodManifestHttpHeader, {url.spec()},
- nullptr);
- log.Error(*out_error_message);
- return GURL();
- }
-
- for (const auto& value : link_header_util::SplitLinkHeader(link_header)) {
- std::string payment_method_manifest_url;
- std::unordered_map<std::string, base::Optional<std::string>> params;
- if (!link_header_util::ParseLinkHeaderValue(
- value.first, value.second, &payment_method_manifest_url, &params)) {
- continue;
- }
-
- auto rel = params.find("rel");
- if (rel == params.end())
- continue;
+// Invokes |callback| with |error_format|.
+void RespondWithError(const base::StringPiece& error_format,
+ const GURL& final_url,
+ const ErrorLogger& log,
+ PaymentManifestDownloadCallback callback) {
+ std::string error_message = base::ReplaceStringPlaceholders(
+ error_format, {final_url.spec()}, nullptr);
+ log.Error(error_message);
+ std::move(callback).Run(final_url, std::string(), error_message);
+}
- std::vector<std::string> rel_parts =
- base::SplitString(rel->second.value_or(""), HTTP_LWS,
- base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- if (base::Contains(rel_parts, "payment-method-manifest"))
- return url.Resolve(payment_method_manifest_url);
+// Invokes the |callback| with |response_body|. If |response_body| is empty,
+// then invokes |callback| with |empty_error_format|.
+void RespondWithContent(const std::string& response_body,
+ const base::StringPiece& empty_error_format,
+ const GURL& final_url,
+ const ErrorLogger& log,
+ PaymentManifestDownloadCallback callback) {
+ if (response_body.empty()) {
+ RespondWithError(empty_error_format, final_url, log, std::move(callback));
+ } else {
+ std::move(callback).Run(final_url, response_body, std::string());
}
-
- *out_error_message = base::ReplaceStringPlaceholders(
- errors::kNoLinkRelPaymentMethodManifestHttpHeader, {url.spec()}, nullptr);
- log.Error(*out_error_message);
- return GURL();
}
bool IsValidManifestUrl(const GURL& url,
@@ -126,22 +97,6 @@ GURL ParseRedirectUrl(const net::RedirectInfo& redirect_info,
return redirect_info.new_url;
}
-std::string ParseResponseContent(
- const GURL& final_url,
- const std::string& response_body,
- scoped_refptr<net::HttpResponseHeaders> headers,
- const ErrorLogger& log,
- std::string* out_error_message) {
- if (!headers || headers->response_code() != net::HTTP_OK) {
- *out_error_message = base::ReplaceStringPlaceholders(
- errors::kPaymentManifestDownloadFailed, {final_url.spec()}, nullptr);
- log.Error(*out_error_message);
- return std::string();
- }
-
- return response_body;
-}
-
} // namespace
PaymentManifestDownloader::PaymentManifestDownloader(
@@ -155,20 +110,24 @@ PaymentManifestDownloader::PaymentManifestDownloader(
PaymentManifestDownloader::~PaymentManifestDownloader() {}
void PaymentManifestDownloader::DownloadPaymentMethodManifest(
+ const url::Origin& merchant_origin,
const GURL& url,
PaymentManifestDownloadCallback callback) {
DCHECK(UrlUtil::IsValidManifestUrl(url));
// Restrict number of redirects for efficiency and breaking circle.
- InitiateDownload(url, "HEAD",
+ InitiateDownload(merchant_origin, url,
+ Download::Type::RESPONSE_BODY_OR_LINK_HEADER,
/*allowed_number_of_redirects=*/3, std::move(callback));
}
void PaymentManifestDownloader::DownloadWebAppManifest(
+ const url::Origin& payment_method_manifest_origin,
const GURL& url,
PaymentManifestDownloadCallback callback) {
DCHECK(UrlUtil::IsValidManifestUrl(url));
- InitiateDownload(url, "GET", /*allowed_number_of_redirects=*/0,
- std::move(callback));
+ InitiateDownload(payment_method_manifest_origin, url,
+ Download::Type::RESPONSE_BODY,
+ /*allowed_number_of_redirects=*/0, std::move(callback));
}
GURL PaymentManifestDownloader::FindTestServerURL(const GURL& url) const {
@@ -193,7 +152,7 @@ void PaymentManifestDownloader::OnURLLoaderRedirect(
// Manually follow some type of redirects.
std::string error_message;
if (download->allowed_number_of_redirects > 0) {
- DCHECK(download->method == "HEAD");
+ DCHECK_EQ(Download::Type::RESPONSE_BODY_OR_LINK_HEADER, download->type);
GURL redirect_url = ParseRedirectUrl(redirect_info, download->original_url,
*log_, &error_message);
if (!redirect_url.is_empty()) {
@@ -201,7 +160,9 @@ void PaymentManifestDownloader::OnURLLoaderRedirect(
if (net::registry_controlled_domains::SameDomainOrHost(
download->original_url, redirect_url,
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
- InitiateDownload(redirect_url, "HEAD",
+ // Redirects preserve the original request initiator.
+ InitiateDownload(download->request_initiator, redirect_url,
+ Download::Type::RESPONSE_BODY_OR_LINK_HEADER,
--download->allowed_number_of_redirects,
std::move(download->callback));
return;
@@ -247,38 +208,88 @@ void PaymentManifestDownloader::OnURLLoaderCompleteInternal(
downloads_.erase(download_it);
std::string error_message;
- if (download->method == "GET") {
- std::string content = ParseResponseContent(final_url, response_body,
- headers, *log_, &error_message);
- std::move(download->callback).Run(final_url, content, error_message);
+ if (download->type == Download::Type::RESPONSE_BODY) {
+ if (!headers || headers->response_code() != net::HTTP_OK) {
+ RespondWithError(errors::kPaymentManifestDownloadFailed, final_url, *log_,
+ std::move(download->callback));
+ } else {
+ RespondWithContent(response_body, errors::kNoContentInPaymentManifest,
+ final_url, *log_, std::move(download->callback));
+ }
return;
}
- DCHECK_EQ("HEAD", download->method);
- GURL payment_method_manifest_url =
- ParseResponseHeader(final_url, headers, *log_, &error_message);
- if (!payment_method_manifest_url.is_valid()) {
- std::move(download->callback).Run(final_url, std::string(), error_message);
+ DCHECK_EQ(Download::Type::RESPONSE_BODY_OR_LINK_HEADER, download->type);
+
+ if (!headers) {
+ RespondWithContent(response_body, errors::kNoContentAndNoLinkHeader,
+ final_url, *log_, std::move(download->callback));
return;
}
- if (!IsValidManifestUrl(payment_method_manifest_url, *log_, &error_message)) {
- std::move(download->callback).Run(final_url, std::string(), error_message);
+ if (headers->response_code() != net::HTTP_OK &&
+ headers->response_code() != net::HTTP_NO_CONTENT) {
+ RespondWithError(errors::kPaymentManifestDownloadFailed, final_url, *log_,
+ std::move(download->callback));
return;
}
- if (!url::IsSameOriginWith(final_url, payment_method_manifest_url)) {
- error_message = base::ReplaceStringPlaceholders(
- errors::kCrossOriginPaymentMethodManifestNotAllowed,
- {payment_method_manifest_url.spec(), final_url.spec()}, nullptr);
- log_->Error(error_message);
- std::move(download->callback).Run(final_url, std::string(), error_message);
+ std::string link_header;
+ headers->GetNormalizedHeader("link", &link_header);
+ if (link_header.empty()) {
+ RespondWithContent(response_body, errors::kNoContentAndNoLinkHeader,
+ final_url, *log_, std::move(download->callback));
return;
}
- InitiateDownload(payment_method_manifest_url, "GET",
- /*allowed_number_of_redirects=*/0,
- std::move(download->callback));
+ for (const auto& value : link_header_util::SplitLinkHeader(link_header)) {
+ std::string link_url;
+ std::unordered_map<std::string, base::Optional<std::string>> params;
+ if (!link_header_util::ParseLinkHeaderValue(value.first, value.second,
+ &link_url, &params)) {
+ continue;
+ }
+
+ auto rel = params.find("rel");
+ if (rel == params.end())
+ continue;
+
+ std::vector<std::string> rel_parts =
+ base::SplitString(rel->second.value_or(""), HTTP_LWS,
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ if (base::Contains(rel_parts, "payment-method-manifest")) {
+ GURL payment_method_manifest_url = final_url.Resolve(link_url);
+
+ if (!IsValidManifestUrl(payment_method_manifest_url, *log_,
+ &error_message)) {
+ std::move(download->callback)
+ .Run(final_url, std::string(), error_message);
+ return;
+ }
+
+ if (!url::IsSameOriginWith(final_url, payment_method_manifest_url)) {
+ error_message = base::ReplaceStringPlaceholders(
+ errors::kCrossOriginPaymentMethodManifestNotAllowed,
+ {payment_method_manifest_url.spec(), final_url.spec()}, nullptr);
+ log_->Error(error_message);
+ std::move(download->callback)
+ .Run(final_url, std::string(), error_message);
+ return;
+ }
+
+ // The request initiator for the payment method manifest is the origin of
+ // the GET request with the HTTP link header.
+ // https://github.com/w3c/webappsec-fetch-metadata/issues/30
+ InitiateDownload(
+ url::Origin::Create(final_url), payment_method_manifest_url,
+ Download::Type::RESPONSE_BODY,
+ /*allowed_number_of_redirects=*/0, std::move(download->callback));
+ return;
+ }
+ }
+
+ RespondWithContent(response_body, errors::kNoContentAndNoLinkHeader,
+ final_url, *log_, std::move(download->callback));
}
network::SimpleURLLoader* PaymentManifestDownloader::GetLoaderForTesting() {
@@ -292,12 +303,18 @@ GURL PaymentManifestDownloader::GetLoaderOriginalURLForTesting() {
}
void PaymentManifestDownloader::InitiateDownload(
+ const url::Origin& request_initiator,
const GURL& url,
- const std::string& method,
+ Download::Type download_type,
int allowed_number_of_redirects,
PaymentManifestDownloadCallback callback) {
DCHECK(UrlUtil::IsValidManifestUrl(url));
+ // Only initial download of the payment method manifest (which might contain
+ // an HTTP Link header) is allowed to redirect.
+ DCHECK(allowed_number_of_redirects == 0 ||
+ download_type == Download::Type::RESPONSE_BODY_OR_LINK_HEADER);
+
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("payment_manifest_downloader", R"(
semantics {
@@ -319,8 +336,9 @@ void PaymentManifestDownloader::InitiateDownload(
policy_exception_justification: "Not implemented."
})");
auto resource_request = std::make_unique<network::ResourceRequest>();
+ resource_request->request_initiator = request_initiator;
resource_request->url = url;
- resource_request->method = method;
+ resource_request->method = "GET";
resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
std::unique_ptr<network::SimpleURLLoader> loader =
network::SimpleURLLoader::Create(std::move(resource_request),
@@ -334,7 +352,8 @@ void PaymentManifestDownloader::InitiateDownload(
weak_ptr_factory_.GetWeakPtr(), loader.get()));
auto download = std::make_unique<Download>();
- download->method = method;
+ download->request_initiator = request_initiator;
+ download->type = download_type;
download->original_url = url;
download->loader = std::move(loader);
download->callback = std::move(callback);
diff --git a/chromium/components/payments/core/payment_manifest_downloader.h b/chromium/components/payments/core/payment_manifest_downloader.h
index 099d5cebbf6..b638801bfd0 100644
--- a/chromium/components/payments/core/payment_manifest_downloader.h
+++ b/chromium/components/payments/core/payment_manifest_downloader.h
@@ -16,6 +16,7 @@
#include "base/memory/weak_ptr.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h"
#include "url/gurl.h"
+#include "url/origin.h"
namespace net {
class HttpResponseHeaders;
@@ -36,19 +37,24 @@ class ErrorLogger;
//
// Download failure results in empty contents. Failure to download the manifest
// can happen because of the following reasons:
-// - HTTP response code is not 200. (204 is also allowed for HEAD request.)
-// - HTTP GET on the manifest URL returns empty content.
+// - HTTP response code is not 200. (204 is also allowed for payment method
+// manifest.)
//
// In the case of a payment method manifest download, can also fail when:
// - More than three redirects.
// - Cross-site redirects.
-// - HTTP response headers are absent.
-// - HTTP response headers do not contain Link headers.
-// - Link header does not contain rel="payment-method-manifest".
-// - Link header does not contain a valid URL of the same origin.
+// - HTTP GET on the manifest URL returns empty content and:
+// - HTTP response headers are absent.
+// - HTTP response headers do not contain Link headers.
+// - Link header does not contain rel="payment-method-manifest".
+// - Link header does not contain a valid URL of the same origin.
+// - After following the Link header:
+// - There's a redirect.
+// - HTTP GET returns empty content.
//
// In the case of a web app manifest download, can also also fail when:
// - There's a redirect.
+// - HTTP GET on the manifest URL returns empty content.
using PaymentManifestDownloadCallback =
base::OnceCallback<void(const GURL& url,
const std::string& contents,
@@ -58,9 +64,9 @@ using PaymentManifestDownloadCallback =
// payment method name that is a URL with HTTPS scheme, e.g.,
// https://bobpay.com.
//
-// The downloader follows up to three redirects for the HEAD request only (used
-// for payment method manifests). Three is enough for known legitimate use cases
-// and seems like a good upper bound.
+// The downloader follows up to three redirects for the payment method manifest
+// request only. Three is enough for known legitimate use cases and seems like a
+// good upper bound.
//
// The command line must be initialized to use this class in tests, because it
// checks for --unsafely-treat-insecure-origin-as-secure=<origin> flag. For
@@ -74,34 +80,43 @@ class PaymentManifestDownloader {
virtual ~PaymentManifestDownloader();
- // Download a payment method manifest via two consecutive HTTP requests:
- //
- // 1) HEAD request for the payment method name. The HTTP response header is
- // parsed for Link header that points to the location of the payment method
- // manifest file. Example of a relative location:
+ // Download a payment method manifest from |url| via a GET. The HTTP response
+ // header is parsed for Link header. If there is no Link header, then the body
+ // is returned. If there's a Link header, then it is followed exactly once.
+ // Example header:
//
// Link: <data/payment-manifest.json>; rel="payment-method-manifest"
//
- // (This is relative to the payment method URL.) Example of an absolute
- // location:
+ // (This is relative to the payment method URL.) Example of an absolute
+ // location:
//
// Link: <https://bobpay.com/data/payment-manifest.json>;
// rel="payment-method-manifest"
//
- // The absolute location must use HTTPS scheme.
+ // The absolute location must use HTTPS scheme.
//
- // 2) GET request for the payment method manifest file.
+ // |merchant_origin| should be the origin of the iframe that created the
+ // PaymentRequest object. It is used by security features like
+ // 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'.
//
- // |url| should be a valid URL with HTTPS scheme.
- void DownloadPaymentMethodManifest(const GURL& url,
+ // |url| should be valid according to UrlUtil::IsValidManifestUrl() to
+ // download.
+ void DownloadPaymentMethodManifest(const url::Origin& merchant_origin,
+ const GURL& url,
PaymentManifestDownloadCallback callback);
- // Download a web app manifest via a single HTTP request:
+ // Download a web app manifest from |url| via a single HTTP request:
//
// 1) GET request for the payment method name.
//
- // |url| should be a valid URL with HTTPS scheme.
- void DownloadWebAppManifest(const GURL& url,
+ // |payment_method_manifest_origin| should be the origin of the payment method
+ // manifest that is pointing to this web app manifest. It is used for security
+ // features like 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'.
+ //
+ // |url| should be valid according to UrlUtil::IsValidManifestUrl() to
+ // download.
+ void DownloadWebAppManifest(const url::Origin& payment_method_manifest_origin,
+ const GURL& url,
PaymentManifestDownloadCallback callback);
// Overridden in TestDownloader to convert |url| to a test server URL. The
@@ -115,11 +130,17 @@ class PaymentManifestDownloader {
// Information about an ongoing download request.
struct Download {
+ enum class Type {
+ RESPONSE_BODY_OR_LINK_HEADER,
+ RESPONSE_BODY,
+ };
+
Download();
~Download();
int allowed_number_of_redirects = 0;
- std::string method;
+ Type type = Type::RESPONSE_BODY;
+ url::Origin request_initiator;
GURL original_url;
std::unique_ptr<network::SimpleURLLoader> loader;
PaymentManifestDownloadCallback callback;
@@ -150,8 +171,9 @@ class PaymentManifestDownloader {
GURL GetLoaderOriginalURLForTesting();
// Overridden in TestDownloader.
- virtual void InitiateDownload(const GURL& url,
- const std::string& method,
+ virtual void InitiateDownload(const url::Origin& request_initiator,
+ const GURL& url,
+ Download::Type download_type,
int allowed_number_of_redirects,
PaymentManifestDownloadCallback callback);
diff --git a/chromium/components/payments/core/payment_manifest_downloader_unittest.cc b/chromium/components/payments/core/payment_manifest_downloader_unittest.cc
index d60c654298f..2fa43962b36 100644
--- a/chromium/components/payments/core/payment_manifest_downloader_unittest.cc
+++ b/chromium/components/payments/core/payment_manifest_downloader_unittest.cc
@@ -22,12 +22,20 @@ namespace {
using testing::_;
-static const char kNoError[] = "";
+static constexpr char kNoContent[] = "";
+static constexpr char kNoError[] = "";
+static constexpr char kNoLinkHeader[] = "";
+static constexpr char kNoResponseBody[] = "";
} // namespace
class PaymentMethodManifestDownloaderTest : public testing::Test {
- public:
+ protected:
+ enum class Headers {
+ kSend,
+ kOmit,
+ };
+
PaymentMethodManifestDownloaderTest()
: test_url_("https://bobpay.com"),
shared_url_loader_factory_(
@@ -36,40 +44,39 @@ class PaymentMethodManifestDownloaderTest : public testing::Test {
downloader_(std::make_unique<ErrorLogger>(),
shared_url_loader_factory_) {
downloader_.DownloadPaymentMethodManifest(
- test_url_,
+ url::Origin::Create(GURL("https://chromium.org")), test_url_,
base::BindOnce(&PaymentMethodManifestDownloaderTest::OnManifestDownload,
base::Unretained(this)));
}
- ~PaymentMethodManifestDownloaderTest() override {}
-
MOCK_METHOD3(OnManifestDownload,
void(const GURL& unused_url_after_redirects,
const std::string& content,
const std::string& error_message));
- void CallComplete(int response_code = 200,
- const std::string& link_header = std::string(),
- const std::string& response_body = std::string(),
- bool send_headers = true) {
+ void ServerResponse(int response_code,
+ Headers send_headers,
+ const std::string& link_header,
+ const std::string& response_body) {
scoped_refptr<net::HttpResponseHeaders> headers;
- if (send_headers) {
+ if (send_headers == Headers::kSend) {
headers = base::MakeRefCounted<net::HttpResponseHeaders>(std::string());
headers->ReplaceStatusLine(base::StringPrintf(
"HTTP/1.1 %d %s", response_code,
net::GetHttpReasonPhrase(
static_cast<net::HttpStatusCode>(response_code))));
+
+ if (!link_header.empty())
+ headers->AddHeader(link_header);
}
- if (!link_header.empty())
- headers->AddHeader(link_header);
downloader_.OnURLLoaderCompleteInternal(
downloader_.GetLoaderForTesting(),
downloader_.GetLoaderOriginalURLForTesting(), response_body, headers,
net::OK);
}
- void CallRedirect(int redirect_code, const GURL& new_url) {
+ void ServerRedirect(int redirect_code, const GURL& new_url) {
net::RedirectInfo redirect_info;
redirect_info.status_code = redirect_code;
redirect_info.new_url = new_url;
@@ -88,127 +95,247 @@ class PaymentMethodManifestDownloaderTest : public testing::Test {
network::TestURLLoaderFactory test_factory_;
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
PaymentManifestDownloader downloader_;
-
- DISALLOW_COPY_AND_ASSIGN(PaymentMethodManifestDownloaderTest);
};
-TEST_F(PaymentMethodManifestDownloaderTest, HttpHeadResponse404IsFailure) {
+TEST_F(PaymentMethodManifestDownloaderTest, FirstHttpResponse404IsFailure) {
+ EXPECT_CALL(
+ *this,
+ OnManifestDownload(
+ _, kNoContent,
+ "Unable to download payment manifest \"https://bobpay.com/\"."));
+
+ ServerResponse(404, Headers::kSend, kNoLinkHeader, kNoResponseBody);
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest,
+ NoHttpHeadersAndEmptyResponseBodyIsFailure) {
EXPECT_CALL(*this,
OnManifestDownload(
- _, std::string(),
- "Unable to make a HEAD request to \"https://bobpay.com/\" "
- "for payment method manifest."));
+ _, kNoContent,
+ "No content and no \"Link: rel=payment-method-manifest\" "
+ "HTTP header found at \"https://bobpay.com/\"."));
- CallComplete(404);
+ ServerResponse(200, Headers::kOmit, kNoLinkHeader, kNoResponseBody);
}
-TEST_F(PaymentMethodManifestDownloaderTest, NoHttpHeadersIsFailure) {
- EXPECT_CALL(
- *this, OnManifestDownload(_, std::string(),
- "No \"Link: rel=payment-method-manifest\" HTTP "
- "header found at \"https://bobpay.com/\"."));
+TEST_F(PaymentMethodManifestDownloaderTest,
+ NoHttpHeadersButWithResponseBodyIsSuccess) {
+ EXPECT_CALL(*this, OnManifestDownload(_, "response body", kNoError));
- CallComplete(200, std::string(), std::string(), false);
+ ServerResponse(200, Headers::kOmit, kNoLinkHeader, "response body");
}
-TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpHeaderIsFailure) {
+TEST_F(PaymentMethodManifestDownloaderTest,
+ EmptyHttpHeaderAndEmptyResponseBodyIsFailure) {
EXPECT_CALL(
- *this, OnManifestDownload(_, std::string(),
- "No \"Link: rel=payment-method-manifest\" HTTP "
- "header found at \"https://bobpay.com/\"."));
+ *this, OnManifestDownload(
+ _, kNoContent,
+ "No content and no \"Link: rel=payment-method-manifest\" HTTP "
+ "header found at \"https://bobpay.com/\"."));
- CallComplete(200);
+ ServerResponse(200, Headers::kSend, kNoLinkHeader, kNoResponseBody);
}
-TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpLinkHeaderIsFailure) {
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders(std::string()));
- EXPECT_CALL(
- *this, OnManifestDownload(_, std::string(),
- "No \"Link: rel=payment-method-manifest\" HTTP "
- "header found at \"https://bobpay.com/\"."));
+TEST_F(PaymentMethodManifestDownloaderTest,
+ EmptyHttpHeaderButWithResponseBodyIsSuccess) {
+ EXPECT_CALL(*this, OnManifestDownload(_, "response content", kNoError));
- CallComplete(200, "Link:");
+ ServerResponse(200, Headers::kSend, kNoLinkHeader, "response content");
}
-TEST_F(PaymentMethodManifestDownloaderTest, NoRelInHttpLinkHeaderIsFailure) {
- EXPECT_CALL(
- *this, OnManifestDownload(_, std::string(),
- "No \"Link: rel=payment-method-manifest\" HTTP "
- "header found at \"https://bobpay.com/\"."));
+TEST_F(PaymentMethodManifestDownloaderTest,
+ EmptyHttpLinkHeaderWithoutResponseBodyIsFailure) {
+ EXPECT_CALL(*this,
+ OnManifestDownload(
+ _, kNoContent,
+ "No content and no \"Link: rel=payment-method-manifest\" "
+ "HTTP header found at \"https://bobpay.com/\"."));
- CallComplete(200, "Link: <manifest.json>");
+ ServerResponse(200, Headers::kSend, "Link:", kNoResponseBody);
}
-TEST_F(PaymentMethodManifestDownloaderTest, NoUrlInHttpLinkHeaderIsFailure) {
- EXPECT_CALL(
- *this, OnManifestDownload(_, std::string(),
- "No \"Link: rel=payment-method-manifest\" HTTP "
- "header found at \"https://bobpay.com/\"."));
+TEST_F(PaymentMethodManifestDownloaderTest,
+ EmptyHttpLinkHeaderButWithResponseBodyIsSuccess) {
+ EXPECT_CALL(*this, OnManifestDownload(_, "response body", kNoError));
- CallComplete(200, "Link: rel=payment-method-manifest");
+ ServerResponse(200, Headers::kSend, "Link:", "response body");
}
TEST_F(PaymentMethodManifestDownloaderTest,
- NoManifestRellInHttpLinkHeaderIsFailure) {
- EXPECT_CALL(
- *this, OnManifestDownload(_, std::string(),
- "No \"Link: rel=payment-method-manifest\" HTTP "
- "header found at \"https://bobpay.com/\"."));
+ NoRelInHttpLinkHeaderAndNoResponseBodyIsFailure) {
+ EXPECT_CALL(*this,
+ OnManifestDownload(
+ _, std::string(),
+ "No content and no \"Link: rel=payment-method-manifest\" "
+ "HTTP header found at \"https://bobpay.com/\"."));
- CallComplete(200, "Link: <manifest.json>; rel=web-app-manifest");
+ ServerResponse(200, Headers::kSend, "Link: <manifest.json>", kNoResponseBody);
}
-TEST_F(PaymentMethodManifestDownloaderTest, HttpGetResponse404IsFailure) {
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders(std::string()));
- CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest");
+TEST_F(PaymentMethodManifestDownloaderTest,
+ NoRelInHttpLinkHeaderButWithResponseBodyIsSuccess) {
+ EXPECT_CALL(*this, OnManifestDownload(_, "response body", kNoError));
+
+ ServerResponse(200, Headers::kSend, "Link: <manifest.json>", "response body");
+}
+TEST_F(PaymentMethodManifestDownloaderTest,
+ NoUrlInHttpLinkHeaderAndNoResponseBodyIsFailure) {
EXPECT_CALL(*this,
- OnManifestDownload(_, std::string(),
+ OnManifestDownload(
+ _, kNoContent,
+ "No content and no \"Link: rel=payment-method-manifest\" "
+ "HTTP header found at \"https://bobpay.com/\"."));
+
+ ServerResponse(200, Headers::kSend, "Link: rel=payment-method-manifest",
+ kNoResponseBody);
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest,
+ NoUrlInHttpLinkHeaderButWithResponseBodyIsSuccess) {
+ EXPECT_CALL(*this, OnManifestDownload(_, "response body", kNoError));
+
+ ServerResponse(200, Headers::kSend, "Link: rel=payment-method-manifest",
+ "response body");
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest,
+ NoManifestRellInHttpLinkHeaderAndNoResponseBodyIsFailure) {
+ EXPECT_CALL(*this,
+ OnManifestDownload(
+ _, kNoContent,
+ "No content and no \"Link: rel=payment-method-manifest\" "
+ "HTTP header found at \"https://bobpay.com/\"."));
+
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=web-app-manifest",
+ kNoResponseBody);
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest,
+ NoManifestRellInHttpLinkHeaderButWithResponseBodyIsSuccess) {
+ EXPECT_CALL(*this, OnManifestDownload(_, "response body", kNoError));
+
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=web-app-manifest",
+ "response body");
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, SecondHttpResponse404IsFailure) {
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
+
+ EXPECT_CALL(*this,
+ OnManifestDownload(_, kNoContent,
"Unable to download payment manifest "
"\"https://bobpay.com/manifest.json\"."));
- CallComplete(404);
+ ServerResponse(404, Headers::kSend, kNoLinkHeader, kNoResponseBody);
}
-TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpGetResponseIsFailure) {
- CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest");
+TEST_F(PaymentMethodManifestDownloaderTest, EmptySecondResponseIsFailure) {
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
EXPECT_CALL(*this,
- OnManifestDownload(_, std::string(),
+ OnManifestDownload(_, kNoContent,
+ "No content found in payment manifest "
+ "\"https://bobpay.com/manifest.json\"."));
+
+ ServerResponse(200, Headers::kSend, kNoLinkHeader, kNoResponseBody);
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest,
+ SecondResponseWithoutHeadersIsFailure) {
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
+
+ EXPECT_CALL(*this,
+ OnManifestDownload(_, kNoContent,
"Unable to download payment manifest "
"\"https://bobpay.com/manifest.json\"."));
- CallComplete(200, std::string(), std::string(), false);
+ ServerResponse(200, Headers::kOmit, kNoLinkHeader, kNoResponseBody);
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, NonEmptySecondResponseIsSuccess) {
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
+
+ EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));
+
+ ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content");
}
-TEST_F(PaymentMethodManifestDownloaderTest, NonEmptyHttpGetResponseIsSuccess) {
- CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest");
+TEST_F(PaymentMethodManifestDownloaderTest, FirstResponseCode204IsSuccess) {
+ ServerResponse(204, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));
- CallComplete(200, std::string(), "manifest content");
+ ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content");
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, SecondResponseCode204IsFailure) {
+ ServerResponse(204, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
+
+ EXPECT_CALL(*this,
+ OnManifestDownload(_, kNoContent,
+ "Unable to download payment manifest "
+ "\"https://bobpay.com/manifest.json\"."));
+
+ ServerResponse(204, Headers::kSend, kNoLinkHeader, "manifest content");
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest,
+ SecondResponseWithLinkHeaderAndNoContentIsFailure) {
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
+
+ EXPECT_CALL(*this,
+ OnManifestDownload(_, kNoContent,
+ "No content found in payment manifest "
+ "\"https://bobpay.com/manifest.json\"."));
+
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
}
-TEST_F(PaymentMethodManifestDownloaderTest, HeaderResponseCode204IsSuccess) {
- CallComplete(204, "Link: <manifest.json>; rel=payment-method-manifest");
+TEST_F(PaymentMethodManifestDownloaderTest,
+ SecondResponseWithLinkHeaderAndWithContentReturnsTheContent) {
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));
- CallComplete(200, std::string(), "manifest content");
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ "manifest content");
}
TEST_F(PaymentMethodManifestDownloaderTest, RelativeHttpHeaderLinkUrl) {
- CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest");
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
EXPECT_EQ("https://bobpay.com/manifest.json", GetOriginalURL());
}
TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpsHeaderLinkUrl) {
- CallComplete(200,
- "Link: <https://bobpay.com/manifest.json>; "
- "rel=payment-method-manifest");
+ ServerResponse(200, Headers::kSend,
+ "Link: <https://bobpay.com/manifest.json>; "
+ "rel=payment-method-manifest",
+ kNoResponseBody);
EXPECT_EQ("https://bobpay.com/manifest.json", GetOriginalURL());
}
@@ -217,131 +344,152 @@ TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpHeaderLinkUrl) {
EXPECT_CALL(
*this,
OnManifestDownload(
- _, std::string(),
+ _, kNoContent,
"\"http://bobpay.com/manifest.json\" is not a valid payment manifest "
"URL with HTTPS scheme (or HTTP scheme for localhost)."));
- CallComplete(200,
- "Link: <http://bobpay.com/manifest.json>; "
- "rel=payment-method-manifest");
+ ServerResponse(
+ 200, Headers::kSend,
+ "Link: <http://bobpay.com/manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
}
TEST_F(PaymentMethodManifestDownloaderTest, 300IsUnsupportedRedirect) {
EXPECT_CALL(*this,
OnManifestDownload(
- _, std::string(),
+ _, kNoContent,
"HTTP status code 300 \"Multiple Choices\" not allowed for "
"payment method manifest \"https://bobpay.com/\"."));
- CallRedirect(300, GURL("https://pay.bobpay.com"));
+ ServerRedirect(300, GURL("https://pay.bobpay.com"));
}
TEST_F(PaymentMethodManifestDownloaderTest, 301And302AreSupportedRedirects) {
- CallRedirect(301, GURL("https://pay.bobpay.com"));
+ ServerRedirect(301, GURL("https://pay.bobpay.com"));
EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.com"));
- CallRedirect(302, GURL("https://newpay.bobpay.com"));
+ ServerRedirect(302, GURL("https://newpay.bobpay.com"));
EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.com"));
- CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest");
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));
- CallComplete(200, std::string(), "manifest content");
+ ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content");
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest,
+ CannotRedirectAfterFollowingLinkHeader) {
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
+
+ EXPECT_CALL(*this, OnManifestDownload(
+ _, kNoContent,
+ "Unable to download the payment manifest because "
+ "reached the maximum number of redirects."));
+
+ ServerRedirect(301, GURL("https://pay.bobpay.com"));
}
TEST_F(PaymentMethodManifestDownloaderTest, 302And303AreSupportedRedirects) {
- CallRedirect(302, GURL("https://pay.bobpay.com"));
+ ServerRedirect(302, GURL("https://pay.bobpay.com"));
EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.com"));
- CallRedirect(303, GURL("https://newpay.bobpay.com"));
+ ServerRedirect(303, GURL("https://newpay.bobpay.com"));
EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.com"));
- CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest");
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));
- CallComplete(200, std::string(), "manifest content");
+ ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content");
}
TEST_F(PaymentMethodManifestDownloaderTest, 304IsUnsupportedRedirect) {
EXPECT_CALL(*this,
OnManifestDownload(
- _, std::string(),
+ _, kNoContent,
"HTTP status code 304 \"Not Modified\" not allowed for "
"payment method manifest \"https://bobpay.com/\"."));
- CallRedirect(304, GURL("https://pay.bobpay.com"));
+ ServerRedirect(304, GURL("https://pay.bobpay.com"));
}
TEST_F(PaymentMethodManifestDownloaderTest, 305IsUnsupportedRedirect) {
EXPECT_CALL(*this, OnManifestDownload(
- _, std::string(),
+ _, kNoContent,
"HTTP status code 305 \"Use Proxy\" not allowed for "
"payment method manifest \"https://bobpay.com/\"."));
- CallRedirect(305, GURL("https://pay.bobpay.com"));
+ ServerRedirect(305, GURL("https://pay.bobpay.com"));
}
TEST_F(PaymentMethodManifestDownloaderTest, 307And308AreSupportedRedirects) {
- CallRedirect(307, GURL("https://pay.bobpay.com"));
+ ServerRedirect(307, GURL("https://pay.bobpay.com"));
EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.com"));
- CallRedirect(308, GURL("https://newpay.bobpay.com"));
+ ServerRedirect(308, GURL("https://newpay.bobpay.com"));
EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.com"));
- CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest");
+ ServerResponse(200, Headers::kSend,
+ "Link: <manifest.json>; rel=payment-method-manifest",
+ kNoResponseBody);
EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));
- CallComplete(200, std::string(), "manifest content");
+ ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content");
}
TEST_F(PaymentMethodManifestDownloaderTest, NoMoreThanThreeRedirects) {
- CallRedirect(301, GURL("https://pay.bobpay.com"));
+ ServerRedirect(301, GURL("https://pay.bobpay.com"));
EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.com"));
- CallRedirect(302, GURL("https://oldpay.bobpay.com"));
+ ServerRedirect(302, GURL("https://oldpay.bobpay.com"));
EXPECT_EQ(GetOriginalURL(), GURL("https://oldpay.bobpay.com"));
- CallRedirect(308, GURL("https://newpay.bobpay.com"));
+ ServerRedirect(308, GURL("https://newpay.bobpay.com"));
EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.com"));
EXPECT_CALL(*this, OnManifestDownload(
- _, std::string(),
+ _, kNoContent,
"Unable to download the payment manifest because "
"reached the maximum number of redirects."));
- CallRedirect(308, GURL("https://newpay.bobpay.com"));
+ ServerRedirect(308, GURL("https://newpay.bobpay.com"));
}
TEST_F(PaymentMethodManifestDownloaderTest, InvalidRedirectUrlIsFailure) {
EXPECT_CALL(*this, OnManifestDownload(
- _, std::string(),
+ _, kNoContent,
"\"\" is not a valid payment manifest URL with HTTPS "
"scheme (or HTTP scheme for localhost)."));
- CallRedirect(308, GURL("pay.bobpay.com"));
+ ServerRedirect(308, GURL("pay.bobpay.com"));
}
TEST_F(PaymentMethodManifestDownloaderTest, NotAllowCrossSiteRedirects) {
EXPECT_CALL(
*this,
OnManifestDownload(
- _, std::string(),
+ _, kNoContent,
"Cross-site redirect from \"https://bobpay.com/\" to "
"\"https://alicepay.com/\" not allowed for payment manifests."));
- CallRedirect(301, GURL("https://alicepay.com"));
+ ServerRedirect(301, GURL("https://alicepay.com"));
}
class WebAppManifestDownloaderTest : public testing::Test {
@@ -354,7 +502,7 @@ class WebAppManifestDownloaderTest : public testing::Test {
downloader_(std::make_unique<ErrorLogger>(),
shared_url_loader_factory_) {
downloader_.DownloadWebAppManifest(
- test_url_,
+ url::Origin::Create(test_url_), test_url_,
base::BindOnce(&WebAppManifestDownloaderTest::OnManifestDownload,
base::Unretained(this)));
}
@@ -366,8 +514,7 @@ class WebAppManifestDownloaderTest : public testing::Test {
const std::string& content,
const std::string& error_message));
- void CallComplete(int response_code,
- const std::string& response_body = std::string()) {
+ void ServerResponse(int response_code, const std::string& response_body) {
scoped_refptr<net::HttpResponseHeaders> headers =
base::MakeRefCounted<net::HttpResponseHeaders>(std::string());
headers->ReplaceStatusLine(base::StringPrintf(
@@ -393,22 +540,26 @@ TEST_F(WebAppManifestDownloaderTest, HttpGetResponse404IsFailure) {
EXPECT_CALL(
*this,
OnManifestDownload(
- _, std::string(),
+ _, kNoContent,
"Unable to download payment manifest \"https://bobpay.com/\"."));
- CallComplete(404);
+ ServerResponse(404, kNoResponseBody);
}
TEST_F(WebAppManifestDownloaderTest, EmptyHttpGetResponseIsFailure) {
- EXPECT_CALL(*this, OnManifestDownload(_, std::string(), kNoError));
+ EXPECT_CALL(
+ *this,
+ OnManifestDownload(
+ _, kNoContent,
+ "No content found in payment manifest \"https://bobpay.com/\"."));
- CallComplete(200);
+ ServerResponse(200, kNoResponseBody);
}
TEST_F(WebAppManifestDownloaderTest, NonEmptyHttpGetResponseIsSuccess) {
EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));
- CallComplete(200, "manifest content");
+ ServerResponse(200, "manifest content");
}
} // namespace payments
diff --git a/chromium/components/payments/core/payment_method_data.cc b/chromium/components/payments/core/payment_method_data.cc
index 515cc27fb18..0cfb1f9fc7c 100644
--- a/chromium/components/payments/core/payment_method_data.cc
+++ b/chromium/components/payments/core/payment_method_data.cc
@@ -13,32 +13,10 @@ namespace payments {
namespace {
// These are defined as part of the spec at:
-// https://w3c.github.io/browser-payment-api/#paymentmethoddata-dictionary
+// https://w3c.github.io/payment-method-basic-card/
static const char kMethodDataData[] = "data";
static const char kSupportedMethods[] = "supportedMethods";
static const char kSupportedNetworks[] = "supportedNetworks";
-static const char kSupportedTypes[] = "supportedTypes";
-
-// Converts |supported_type| to |card_type| and returns true on success.
-bool ConvertCardTypeStringToEnum(const std::string& supported_type,
- autofill::CreditCard::CardType* card_type) {
- if (supported_type == "credit") {
- *card_type = autofill::CreditCard::CARD_TYPE_CREDIT;
- return true;
- }
-
- if (supported_type == "debit") {
- *card_type = autofill::CreditCard::CARD_TYPE_DEBIT;
- return true;
- }
-
- if (supported_type == "prepaid") {
- *card_type = autofill::CreditCard::CARD_TYPE_PREPAID;
- return true;
- }
-
- return false;
-}
} // namespace
@@ -48,8 +26,7 @@ PaymentMethodData::~PaymentMethodData() = default;
bool PaymentMethodData::operator==(const PaymentMethodData& other) const {
return supported_method == other.supported_method && data == other.data &&
- supported_networks == other.supported_networks &&
- supported_types == other.supported_types;
+ supported_networks == other.supported_networks;
}
bool PaymentMethodData::operator!=(const PaymentMethodData& other) const {
@@ -59,7 +36,6 @@ bool PaymentMethodData::operator!=(const PaymentMethodData& other) const {
bool PaymentMethodData::FromDictionaryValue(
const base::DictionaryValue& value) {
supported_networks.clear();
- supported_types.clear();
// The value of supportedMethods should be a string.
if (!value.GetString(kSupportedMethods, &supported_method) ||
@@ -68,7 +44,7 @@ bool PaymentMethodData::FromDictionaryValue(
}
// Data is optional, but if a dictionary is present, save a stringified
- // version and attempt to parse supportedNetworks/supportedTypes.
+ // version and attempt to parse supportedNetworks.
const base::DictionaryValue* data_dict = nullptr;
if (value.GetDictionary(kMethodDataData, &data_dict)) {
std::string json_data;
@@ -85,20 +61,6 @@ bool PaymentMethodData::FromDictionaryValue(
supported_networks.push_back(supported_network);
}
}
- const base::ListValue* supported_types_list = nullptr;
- if (data_dict->GetList(kSupportedTypes, &supported_types_list)) {
- for (size_t i = 0; i < supported_types_list->GetSize(); ++i) {
- std::string supported_type;
- if (!supported_types_list->GetString(i, &supported_type) ||
- !base::IsStringASCII(supported_type)) {
- return false;
- }
- autofill::CreditCard::CardType card_type =
- autofill::CreditCard::CARD_TYPE_UNKNOWN;
- if (ConvertCardTypeStringToEnum(supported_type, &card_type))
- supported_types.insert(card_type);
- }
- }
}
return true;
}
diff --git a/chromium/components/payments/core/payment_method_data.h b/chromium/components/payments/core/payment_method_data.h
index e73b7712d04..5a956248f5f 100644
--- a/chromium/components/payments/core/payment_method_data.h
+++ b/chromium/components/payments/core/payment_method_data.h
@@ -44,7 +44,6 @@ class PaymentMethodData {
// When the methods include "basic-card", a list of networks and types that
// are supported.
std::vector<std::string> supported_networks;
- std::set<autofill::CreditCard::CardType> supported_types;
};
} // namespace payments
diff --git a/chromium/components/payments/core/payment_method_data_unittest.cc b/chromium/components/payments/core/payment_method_data_unittest.cc
index be891a43256..815b7374bac 100644
--- a/chromium/components/payments/core/payment_method_data_unittest.cc
+++ b/chromium/components/payments/core/payment_method_data_unittest.cc
@@ -14,12 +14,8 @@ namespace payments {
TEST(PaymentMethodData, FromDictionaryValueSuccess_SupportedMethodsString) {
PaymentMethodData expected;
expected.supported_method = "basic-card";
- expected.data =
- "{\"supportedNetworks\":[\"mastercard\"],"
- "\"supportedTypes\":[\"debit\",\"credit\"]}";
+ expected.data = "{\"supportedNetworks\":[\"mastercard\"]}";
expected.supported_networks.push_back("mastercard");
- expected.supported_types.insert(autofill::CreditCard::CARD_TYPE_DEBIT);
- expected.supported_types.insert(autofill::CreditCard::CARD_TYPE_CREDIT);
base::DictionaryValue method_data_dict;
method_data_dict.SetString("supportedMethods", "basic-card");
@@ -27,10 +23,6 @@ TEST(PaymentMethodData, FromDictionaryValueSuccess_SupportedMethodsString) {
auto supported_networks_list = std::make_unique<base::ListValue>();
supported_networks_list->AppendString("mastercard");
data_dict->Set("supportedNetworks", std::move(supported_networks_list));
- auto supported_types_list = std::make_unique<base::ListValue>();
- supported_types_list->AppendString("debit");
- supported_types_list->AppendString("credit");
- data_dict->Set("supportedTypes", std::move(supported_types_list));
method_data_dict.Set("data", std::move(data_dict));
PaymentMethodData actual;
@@ -100,13 +92,6 @@ TEST(PaymentMethodData, Equality) {
EXPECT_NE(method_data1, method_data2);
method_data2.supported_networks = supported_networks1;
EXPECT_EQ(method_data1, method_data2);
-
- method_data1.supported_types = {autofill::CreditCard::CARD_TYPE_UNKNOWN};
- EXPECT_NE(method_data1, method_data2);
- method_data2.supported_types = {autofill::CreditCard::CARD_TYPE_DEBIT};
- EXPECT_NE(method_data1, method_data2);
- method_data2.supported_types = method_data1.supported_types;
- EXPECT_EQ(method_data1, method_data2);
}
} // namespace payments
diff --git a/chromium/components/payments/core/payment_request_data_util.cc b/chromium/components/payments/core/payment_request_data_util.cc
index f61dc5d8b00..9d7766dc959 100644
--- a/chromium/components/payments/core/payment_request_data_util.cc
+++ b/chromium/components/payments/core/payment_request_data_util.cc
@@ -146,35 +146,6 @@ void ParseSupportedMethods(
}
}
-void ParseSupportedCardTypes(
- const std::vector<PaymentMethodData>& method_data,
- std::set<autofill::CreditCard::CardType>* out_supported_card_types_set) {
- DCHECK(out_supported_card_types_set->empty());
-
- for (const PaymentMethodData& method_data_entry : method_data) {
- // Ignore |supported_types| if |supported_method| is not "basic-card".
- if (method_data_entry.supported_method != methods::kBasicCard)
- continue;
-
- for (const autofill::CreditCard::CardType& card_type :
- method_data_entry.supported_types) {
- out_supported_card_types_set->insert(card_type);
- }
- }
-
- // Omitting the card types means all 3 card types are supported.
- if (out_supported_card_types_set->empty()) {
- out_supported_card_types_set->insert(
- autofill::CreditCard::CARD_TYPE_CREDIT);
- out_supported_card_types_set->insert(autofill::CreditCard::CARD_TYPE_DEBIT);
- out_supported_card_types_set->insert(
- autofill::CreditCard::CARD_TYPE_PREPAID);
- }
-
- // Let the user decide whether an unknown card type should be used.
- out_supported_card_types_set->insert(autofill::CreditCard::CARD_TYPE_UNKNOWN);
-}
-
base::string16 FormatCardNumberForDisplay(const base::string16& card_number) {
base::string16 number = autofill::CreditCard::StripSeparators(card_number);
if (number.empty() || !base::IsAsciiDigit(number[0]))
diff --git a/chromium/components/payments/core/payment_request_data_util.h b/chromium/components/payments/core/payment_request_data_util.h
index ae296247d73..633d5173260 100644
--- a/chromium/components/payments/core/payment_request_data_util.h
+++ b/chromium/components/payments/core/payment_request_data_util.h
@@ -59,14 +59,6 @@ void ParseSupportedMethods(
std::vector<GURL>* out_url_payment_method_identifiers,
std::set<std::string>* out_payment_method_identifiers);
-// Parses the supported card types (e.g., credit, debit, prepaid) from
-// supportedTypes. |out_supported_card_types_set| is expected to be empty. It
-// will always contain autofill::CreditCard::CARD_TYPE_UNKNOWN after the call.
-// Also, it gets filled with all of the card types if supportedTypes is empty.
-void ParseSupportedCardTypes(
- const std::vector<PaymentMethodData>& method_data,
- std::set<autofill::CreditCard::CardType>* out_supported_card_types_set);
-
// Formats |card_number| for display. For example, "4111111111111111" is
// formatted into "4111 1111 1111 1111". This method does not format masked card
// numbers, which start with a letter.
diff --git a/chromium/components/payments/core/payment_request_data_util_unittest.cc b/chromium/components/payments/core/payment_request_data_util_unittest.cc
index 10766484c71..b034fca5f37 100644
--- a/chromium/components/payments/core/payment_request_data_util_unittest.cc
+++ b/chromium/components/payments/core/payment_request_data_util_unittest.cc
@@ -8,6 +8,7 @@
#include "base/json/json_writer.h"
#include "base/macros.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -69,24 +70,26 @@ TEST(PaymentRequestDataUtilTest, GetBasicCardResponseFromAutofillCreditCard) {
->ToDictionaryValue();
std::string json_response;
base::JSONWriter::Write(*response_value, &json_response);
- EXPECT_EQ(
- "{\"billingAddress\":"
- "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
- "\"city\":\"Elysium\","
- "\"country\":\"US\","
- "\"dependentLocality\":\"\","
- "\"organization\":\"Underworld\","
- "\"phone\":\"16502111111\","
- "\"postalCode\":\"91111\","
- "\"recipient\":\"John H. Doe\","
- "\"region\":\"CA\","
- "\"sortingCode\":\"\"},"
- "\"cardNumber\":\"4111111111111111\","
- "\"cardSecurityCode\":\"123\","
- "\"cardholderName\":\"Test User\","
- "\"expiryMonth\":\"11\","
- "\"expiryYear\":\"2022\"}",
- json_response);
+ EXPECT_EQ(base::StringPrintf(
+ "{\"billingAddress\":"
+ "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
+ "\"city\":\"Elysium\","
+ "\"country\":\"US\","
+ "\"dependentLocality\":\"\","
+ "\"organization\":\"Underworld\","
+ "\"phone\":\"16502111111\","
+ "\"postalCode\":\"91111\","
+ "\"recipient\":\"John H. Doe\","
+ "\"region\":\"CA\","
+ "\"sortingCode\":\"\"},"
+ "\"cardNumber\":\"4111111111111111\","
+ "\"cardSecurityCode\":\"123\","
+ "\"cardholderName\":\"Test User\","
+ "\"expiryMonth\":\"%s\","
+ "\"expiryYear\":\"%s\"}",
+ base::UTF16ToUTF8(card.Expiration2DigitMonthAsString()).c_str(),
+ base::UTF16ToUTF8(card.Expiration4DigitYearAsString()).c_str()),
+ json_response);
}
// A test fixture to check ParseSupportedMethods() returns empty supported
diff --git a/chromium/components/payments/core/strings_util.cc b/chromium/components/payments/core/strings_util.cc
index dab19470d47..1a8b0be84c6 100644
--- a/chromium/components/payments/core/strings_util.cc
+++ b/chromium/components/payments/core/strings_util.cc
@@ -14,27 +14,6 @@
#include "ui/base/l10n/l10n_util.h"
namespace payments {
-namespace {
-
-constexpr size_t kNone = 0;
-constexpr size_t kCredit = 1;
-constexpr size_t kDebit = 2;
-constexpr size_t kPrepaid = 4;
-
-size_t getCardTypeBitmask(
- const std::set<autofill::CreditCard::CardType>& types) {
- return (types.find(autofill::CreditCard::CARD_TYPE_CREDIT) != types.end()
- ? kCredit
- : kNone) |
- (types.find(autofill::CreditCard::CARD_TYPE_DEBIT) != types.end()
- ? kDebit
- : kNone) |
- (types.find(autofill::CreditCard::CARD_TYPE_PREPAID) != types.end()
- ? kPrepaid
- : kNone);
-}
-
-} // namespace
base::string16 GetShippingAddressLabelFormAutofillProfile(
const autofill::AutofillProfile& profile,
@@ -173,47 +152,4 @@ base::string16 GetShippingOptionSectionString(
}
}
-base::string16 GetAcceptedCardTypesText(
- const std::set<autofill::CreditCard::CardType>& types) {
- int string_ids[8];
-
- string_ids[kNone] = IDS_PAYMENTS_ACCEPTED_CARDS_LABEL;
- string_ids[kCredit | kDebit | kPrepaid] = IDS_PAYMENTS_ACCEPTED_CARDS_LABEL;
-
- string_ids[kCredit] = IDS_PAYMENTS_ACCEPTED_CREDIT_CARDS_LABEL;
- string_ids[kDebit] = IDS_PAYMENTS_ACCEPTED_DEBIT_CARDS_LABEL;
- string_ids[kPrepaid] = IDS_PAYMENTS_ACCEPTED_PREPAID_CARDS_LABEL;
-
- string_ids[kCredit | kDebit] = IDS_PAYMENTS_ACCEPTED_CREDIT_DEBIT_CARDS_LABEL;
- string_ids[kCredit | kPrepaid] =
- IDS_PAYMENTS_ACCEPTED_CREDIT_PREPAID_CARDS_LABEL;
- string_ids[kDebit | kPrepaid] =
- IDS_PAYMENTS_ACCEPTED_DEBIT_PREPAID_CARDS_LABEL;
-
- return l10n_util::GetStringUTF16(string_ids[getCardTypeBitmask(types)]);
-}
-
-base::string16 GetCardTypesAreAcceptedText(
- const std::set<autofill::CreditCard::CardType>& types) {
- int string_ids[8];
-
- string_ids[kNone] = 0;
- string_ids[kCredit | kDebit | kPrepaid] = 0;
-
- string_ids[kCredit] = IDS_PAYMENTS_CREDIT_CARDS_ARE_ACCEPTED_LABEL;
- string_ids[kDebit] = IDS_PAYMENTS_DEBIT_CARDS_ARE_ACCEPTED_LABEL;
- string_ids[kPrepaid] = IDS_PAYMENTS_PREPAID_CARDS_ARE_ACCEPTED_LABEL;
-
- string_ids[kCredit | kDebit] =
- IDS_PAYMENTS_CREDIT_DEBIT_CARDS_ARE_ACCEPTED_LABEL;
- string_ids[kCredit | kPrepaid] =
- IDS_PAYMENTS_CREDIT_PREPAID_CARDS_ARE_ACCEPTED_LABEL;
- string_ids[kDebit | kPrepaid] =
- IDS_PAYMENTS_DEBIT_PREPAID_CARDS_ARE_ACCEPTED_LABEL;
-
- int string_id = string_ids[getCardTypeBitmask(types)];
- return string_id == 0 ? base::string16()
- : l10n_util::GetStringUTF16(string_id);
-}
-
} // namespace payments
diff --git a/chromium/components/payments/core/strings_util.h b/chromium/components/payments/core/strings_util.h
index efdf5c364ef..3fcd43a6039 100644
--- a/chromium/components/payments/core/strings_util.h
+++ b/chromium/components/payments/core/strings_util.h
@@ -61,19 +61,6 @@ base::string16 GetChooseShippingOptionButtonLabel(
base::string16 GetShippingOptionSectionString(
PaymentShippingType shipping_type);
-// Returns the label "Accepted cards" that is customized based on the
-// accepted card |types|. For example, "Accepted debit cards". If |types| is
-// empty or contains all possible values, then returns the generic "Accepted
-// cards" string.
-base::string16 GetAcceptedCardTypesText(
- const std::set<autofill::CreditCard::CardType>& types);
-
-// Returns the label "Cards are accepted" that is customized based on the
-// accepted card |types|. For example, "Debit cards are accepted". If |types| is
-// empty or contains all possible values, then returns an empty string.
-base::string16 GetCardTypesAreAcceptedText(
- const std::set<autofill::CreditCard::CardType>& types);
-
} // namespace payments
#endif // COMPONENTS_PAYMENTS_CORE_STRINGS_UTIL_H_
diff --git a/chromium/components/payments/core/strings_util_unittest.cc b/chromium/components/payments/core/strings_util_unittest.cc
deleted file mode 100644
index e2e82395ac6..00000000000
--- a/chromium/components/payments/core/strings_util_unittest.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/payments/core/strings_util.h"
-
-#include <string>
-#include <vector>
-
-#include "base/stl_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace payments {
-namespace {
-
-using CardType = ::autofill::CreditCard::CardType;
-
-constexpr CardType CREDIT = ::autofill::CreditCard::CARD_TYPE_CREDIT;
-constexpr CardType DEBIT = ::autofill::CreditCard::CARD_TYPE_DEBIT;
-constexpr CardType PREPAID = ::autofill::CreditCard::CARD_TYPE_PREPAID;
-constexpr CardType UNKNOWN = ::autofill::CreditCard::CARD_TYPE_UNKNOWN;
-
-} // namespace
-
-#if defined(OS_MACOSX)
-TEST(StringsUtilTest, GetAcceptedCardTypesText) {
- static const struct {
- std::vector<CardType> card_types;
- const char* const expected_text;
- } kTestCases[] = {
- {std::vector<CardType>(), "Accepted Cards"},
- {{UNKNOWN}, "Accepted Cards"},
- {{CREDIT}, "Accepted Credit Cards"},
- {{DEBIT}, "Accepted Debit Cards"},
- {{PREPAID}, "Accepted Prepaid Cards"},
- {{CREDIT, DEBIT}, "Accepted Credit and Debit Cards"},
- {{CREDIT, PREPAID}, "Accepted Credit and Prepaid Cards"},
- {{DEBIT, PREPAID}, "Accepted Debit and Prepaid Cards"},
- {{CREDIT, DEBIT, PREPAID}, "Accepted Cards"},
- };
- for (size_t i = 0; i < base::size(kTestCases); ++i) {
- EXPECT_EQ(
- base::UTF8ToUTF16(kTestCases[i].expected_text),
- GetAcceptedCardTypesText(std::set<CardType>(
- kTestCases[i].card_types.begin(), kTestCases[i].card_types.end())));
- }
-}
-#else
-TEST(StringsUtilTest, GetAcceptedCardTypesText) {
- static const struct {
- std::vector<CardType> card_types;
- const char* const expected_text;
- } kTestCases[] = {
- {std::vector<CardType>(), "Accepted cards"},
- {{UNKNOWN}, "Accepted cards"},
- {{CREDIT}, "Accepted credit cards"},
- {{DEBIT}, "Accepted debit cards"},
- {{PREPAID}, "Accepted prepaid cards"},
- {{CREDIT, DEBIT}, "Accepted credit and debit cards"},
- {{CREDIT, PREPAID}, "Accepted credit and prepaid cards"},
- {{DEBIT, PREPAID}, "Accepted debit and prepaid cards"},
- {{CREDIT, DEBIT, PREPAID}, "Accepted cards"},
- };
- for (size_t i = 0; i < base::size(kTestCases); ++i) {
- EXPECT_EQ(
- base::UTF8ToUTF16(kTestCases[i].expected_text),
- GetAcceptedCardTypesText(std::set<CardType>(
- kTestCases[i].card_types.begin(), kTestCases[i].card_types.end())));
- }
-}
-#endif
-
-TEST(StringsUtilTest, GetCardTypesAreAcceptedText) {
- static const struct {
- std::vector<CardType> card_types;
- const char* const expected_text;
- } kTestCases[] = {
- {std::vector<CardType>(), ""},
- {{UNKNOWN}, ""},
- {{CREDIT}, "Credit cards are accepted."},
- {{DEBIT}, "Debit cards are accepted."},
- {{PREPAID}, "Prepaid cards are accepted."},
- {{CREDIT, DEBIT}, "Credit and debit cards are accepted."},
- {{CREDIT, PREPAID}, "Credit and prepaid cards are accepted."},
- {{DEBIT, PREPAID}, "Debit and prepaid cards are accepted."},
- {{CREDIT, DEBIT, PREPAID}, ""},
- };
- for (size_t i = 0; i < base::size(kTestCases); ++i) {
- EXPECT_EQ(
- base::UTF8ToUTF16(kTestCases[i].expected_text),
- GetCardTypesAreAcceptedText(std::set<CardType>(
- kTestCases[i].card_types.begin(), kTestCases[i].card_types.end())));
- }
-}
-
-} // namespace payments
diff --git a/chromium/components/payments/core/test_payment_manifest_downloader.cc b/chromium/components/payments/core/test_payment_manifest_downloader.cc
index 319ef305d5c..f1b8b893784 100644
--- a/chromium/components/payments/core/test_payment_manifest_downloader.cc
+++ b/chromium/components/payments/core/test_payment_manifest_downloader.cc
@@ -27,13 +27,14 @@ void TestDownloader::AddTestServerURL(const std::string& prefix,
}
void TestDownloader::InitiateDownload(
+ const url::Origin& request_initiator,
const GURL& url,
- const std::string& method,
+ Download::Type download_type,
int allowed_number_of_redirects,
PaymentManifestDownloadCallback callback) {
- PaymentManifestDownloader::InitiateDownload(FindTestServerURL(url), method,
- allowed_number_of_redirects,
- std::move(callback));
+ PaymentManifestDownloader::InitiateDownload(
+ request_initiator, FindTestServerURL(url), download_type,
+ allowed_number_of_redirects, std::move(callback));
}
GURL TestDownloader::FindTestServerURL(const GURL& url) const {
diff --git a/chromium/components/payments/core/test_payment_manifest_downloader.h b/chromium/components/payments/core/test_payment_manifest_downloader.h
index 220d7378564..a200a56e256 100644
--- a/chromium/components/payments/core/test_payment_manifest_downloader.h
+++ b/chromium/components/payments/core/test_payment_manifest_downloader.h
@@ -95,8 +95,9 @@ class TestDownloader : public PaymentManifestDownloader {
private:
// PaymentManifestDownloader implementation.
- void InitiateDownload(const GURL& url,
- const std::string& method,
+ void InitiateDownload(const url::Origin& request_initiator,
+ const GURL& url,
+ Download::Type download_type,
int allowed_number_of_redirects,
PaymentManifestDownloadCallback callback) override;
diff --git a/chromium/components/payments/mojom/BUILD.gn b/chromium/components/payments/mojom/BUILD.gn
index 6caf4541a79..2b8def3bc43 100644
--- a/chromium/components/payments/mojom/BUILD.gn
+++ b/chromium/components/payments/mojom/BUILD.gn
@@ -6,9 +6,7 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojom") {
generate_java = true
- sources = [
- "payment_request_data.mojom",
- ]
+ sources = [ "payment_request_data.mojom" ]
# TODO(crbug.com/699569): Convert to use the new JS bindings.
# use_new_js_bindings = false