Commit 20b2b363 authored by Sahel Sharify's avatar Sahel Sharify Committed by Commit Bot

[Payment] Refetch missing icon for already installed PH.

This cl refetches missing icons for already installed payment apps with
web app manifests. Screencast of the fix is attached to the bug.

Bug: 1069010
Change-Id: Ibd1e191f199295fb8301a4202cc7512b66408f05
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2264860
Commit-Queue: Sahel Sharify <sahel@chromium.org>
Reviewed-by: default avatarDanyao Wang <danyao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#782182}
parent c5db059f
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "components/payments/content/icon/icon_size.h" #include "components/payments/content/icon/icon_size.h"
#include "components/payments/core/features.h"
#include "components/payments/core/native_error_strings.h" #include "components/payments/core/native_error_strings.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
...@@ -61,18 +62,32 @@ InstallablePaymentAppCrawler::~InstallablePaymentAppCrawler() {} ...@@ -61,18 +62,32 @@ InstallablePaymentAppCrawler::~InstallablePaymentAppCrawler() {}
void InstallablePaymentAppCrawler::Start( void InstallablePaymentAppCrawler::Start(
const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data, const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data,
std::set<GURL> method_manifest_urls_for_icon_refetch,
FinishedCrawlingCallback callback, FinishedCrawlingCallback callback,
base::OnceClosure finished_using_resources) { base::OnceClosure finished_using_resources) {
callback_ = std::move(callback); callback_ = std::move(callback);
finished_using_resources_ = std::move(finished_using_resources); finished_using_resources_ = std::move(finished_using_resources);
std::set<GURL> manifests_to_download; std::set<GURL> manifests_to_download;
for (const auto& method_data : requested_method_data) { if (method_manifest_urls_for_icon_refetch.empty()) {
if (!base::IsStringUTF8(method_data->supported_method)) // Crawl for JIT installable web apps.
continue; crawling_mode_ = CrawlingMode::kJustInTimeInstallation;
GURL url = GURL(method_data->supported_method); for (const auto& method_data : requested_method_data) {
if (url.is_valid()) { if (!base::IsStringUTF8(method_data->supported_method))
manifests_to_download.insert(url); continue;
GURL url = GURL(method_data->supported_method);
if (url.is_valid()) {
manifests_to_download.insert(url);
}
}
} else {
// Crawl to refetch missing icons of already installed apps.
crawling_mode_ = CrawlingMode::kMissingIconRefetch;
method_manifest_urls_for_icon_refetch_ =
std::move(method_manifest_urls_for_icon_refetch);
for (const auto& method : method_manifest_urls_for_icon_refetch_) {
DCHECK(method.is_valid());
manifests_to_download.insert(method);
} }
} }
...@@ -246,7 +261,10 @@ void InstallablePaymentAppCrawler::OnPaymentWebAppInstallationInfo( ...@@ -246,7 +261,10 @@ void InstallablePaymentAppCrawler::OnPaymentWebAppInstallationInfo(
if (CompleteAndStorePaymentWebAppInfoIfValid( if (CompleteAndStorePaymentWebAppInfoIfValid(
method_manifest_url, web_app_manifest_url, std::move(app_info))) { method_manifest_url, web_app_manifest_url, std::move(app_info))) {
if (!DownloadAndDecodeWebAppIcon(method_manifest_url, web_app_manifest_url, if (!DownloadAndDecodeWebAppIcon(method_manifest_url, web_app_manifest_url,
std::move(icons))) { std::move(icons)) &&
crawling_mode_ == CrawlingMode::kJustInTimeInstallation &&
!base::FeatureList::IsEnabled(
features::kAllowJITInstallationWhenAppIconIsMissing)) {
std::string error_message = base::ReplaceStringPlaceholders( std::string error_message = base::ReplaceStringPlaceholders(
errors::kInvalidWebAppIcon, {web_app_manifest_url.spec()}, nullptr); errors::kInvalidWebAppIcon, {web_app_manifest_url.spec()}, nullptr);
SetFirstError(error_message); SetFirstError(error_message);
...@@ -339,7 +357,9 @@ bool InstallablePaymentAppCrawler::CompleteAndStorePaymentWebAppInfoIfValid( ...@@ -339,7 +357,9 @@ bool InstallablePaymentAppCrawler::CompleteAndStorePaymentWebAppInfoIfValid(
downloader_->FindTestServerURL(GURL(app_info->sw_scope)).spec(); downloader_->FindTestServerURL(GURL(app_info->sw_scope)).spec();
} }
installable_apps_[method_manifest_url] = std::move(app_info); if (crawling_mode_ == CrawlingMode::kJustInTimeInstallation) {
installable_apps_[method_manifest_url] = std::move(app_info);
}
return true; return true;
} }
...@@ -463,20 +483,38 @@ void InstallablePaymentAppCrawler::OnPaymentWebAppIconDownloadAndDecoded( ...@@ -463,20 +483,38 @@ void InstallablePaymentAppCrawler::OnPaymentWebAppIconDownloadAndDecoded(
const GURL& web_app_manifest_url, const GURL& web_app_manifest_url,
const SkBitmap& icon) { const SkBitmap& icon) {
number_of_web_app_icons_to_download_and_decode_--; number_of_web_app_icons_to_download_and_decode_--;
auto it = installable_apps_.find(method_manifest_url);
DCHECK(it != installable_apps_.end()); if (crawling_mode_ == CrawlingMode::kJustInTimeInstallation) {
DCHECK(IsSameOriginWith(GURL(it->second->sw_scope), web_app_manifest_url)); auto it = installable_apps_.find(method_manifest_url);
if (icon.drawsNothing()) { DCHECK(it != installable_apps_.end());
log_.Error( DCHECK(IsSameOriginWith(GURL(it->second->sw_scope), web_app_manifest_url));
"Failed to download or decode the icon from web app manifest \"" + if (icon.drawsNothing() &&
web_app_manifest_url.spec() + "\" for payment handler manifest \"" + !base::FeatureList::IsEnabled(
method_manifest_url.spec() + "\"."); features::kAllowJITInstallationWhenAppIconIsMissing)) {
std::string error_message = base::ReplaceStringPlaceholders( log_.Error(
errors::kInvalidWebAppIcon, {web_app_manifest_url.spec()}, nullptr); "Failed to download or decode the icon from web app manifest \"" +
SetFirstError(error_message); web_app_manifest_url.spec() + "\" for payment handler manifest \"" +
installable_apps_.erase(it); 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 {
it->second->icon = std::make_unique<SkBitmap>(icon);
}
} else { } else {
it->second->icon = std::make_unique<SkBitmap>(icon); DCHECK_EQ(CrawlingMode::kMissingIconRefetch, crawling_mode_);
auto it = method_manifest_urls_for_icon_refetch_.find(method_manifest_url);
DCHECK(it != method_manifest_urls_for_icon_refetch_.end());
if (icon.drawsNothing()) {
log_.Warn("Failed to refetch a valid icon from web app manifest \"" +
web_app_manifest_url.spec() +
"\" for payment handler manifest \"" +
method_manifest_url.spec() + "\".");
} else {
refetched_icons_.insert(std::pair<GURL, std::unique_ptr<SkBitmap>>(
web_app_manifest_url, std::make_unique<SkBitmap>(icon)));
}
} }
FinishCrawlingPaymentAppsIfReady(); FinishCrawlingPaymentAppsIfReady();
...@@ -491,7 +529,8 @@ void InstallablePaymentAppCrawler::FinishCrawlingPaymentAppsIfReady() { ...@@ -491,7 +529,8 @@ void InstallablePaymentAppCrawler::FinishCrawlingPaymentAppsIfReady() {
return; return;
} }
std::move(callback_).Run(std::move(installable_apps_), first_error_message_); std::move(callback_).Run(std::move(installable_apps_),
std::move(refetched_icons_), first_error_message_);
std::move(finished_using_resources_).Run(); std::move(finished_using_resources_).Run();
} }
......
...@@ -40,8 +40,18 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver { ...@@ -40,8 +40,18 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver {
public: public:
using FinishedCrawlingCallback = base::OnceCallback<void( using FinishedCrawlingCallback = base::OnceCallback<void(
std::map<GURL, std::unique_ptr<WebAppInstallationInfo>>, std::map<GURL, std::unique_ptr<WebAppInstallationInfo>>,
std::map<GURL, std::unique_ptr<SkBitmap>>,
const std::string& error_message)>; const std::string& error_message)>;
enum class CrawlingMode {
// In this mode the crawler will crawl for finding JIT installable payment
// apps.
kJustInTimeInstallation,
// In this mode the crawler will crawl for downloading missing icons for
// already installed payment apps.
kMissingIconRefetch,
};
// |merchant_origin| is the origin of the iframe that created the // |merchant_origin| is the origin of the iframe that created the
// PaymentRequest object. It is used by security features like // PaymentRequest object. It is used by security features like
// 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'. // 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'.
...@@ -66,14 +76,15 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver { ...@@ -66,14 +76,15 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver {
// then this object is safe to be deleted. // then this object is safe to be deleted.
void Start( void Start(
const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data, const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data,
std::set<GURL> method_manifest_urls_for_icon_refetch,
FinishedCrawlingCallback callback, FinishedCrawlingCallback callback,
base::OnceClosure finished_using_resources); base::OnceClosure finished_using_resources);
void IgnorePortInOriginComparisonForTesting(); void IgnorePortInOriginComparisonForTesting();
private:
bool IsSameOriginWith(const GURL& a, const GURL& b); bool IsSameOriginWith(const GURL& a, const GURL& b);
private:
void OnPaymentMethodManifestDownloaded( void OnPaymentMethodManifestDownloaded(
const GURL& method_manifest_url, const GURL& method_manifest_url,
const GURL& method_manifest_url_after_redirects, const GURL& method_manifest_url_after_redirects,
...@@ -127,6 +138,8 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver { ...@@ -127,6 +138,8 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver {
size_t number_of_web_app_icons_to_download_and_decode_; size_t number_of_web_app_icons_to_download_and_decode_;
std::set<GURL> downloaded_web_app_manifests_; std::set<GURL> downloaded_web_app_manifests_;
std::map<GURL, std::unique_ptr<WebAppInstallationInfo>> installable_apps_; std::map<GURL, std::unique_ptr<WebAppInstallationInfo>> installable_apps_;
std::map<GURL, std::unique_ptr<SkBitmap>> refetched_icons_;
std::set<GURL> method_manifest_urls_for_icon_refetch_;
// The first error message (if any) to be forwarded to the merchant when // The first error message (if any) to be forwarded to the merchant when
// rejecting the promise returned from PaymentRequest.show(). // rejecting the promise returned from PaymentRequest.show().
...@@ -134,6 +147,8 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver { ...@@ -134,6 +147,8 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver {
bool ignore_port_in_origin_comparison_for_testing_ = false; bool ignore_port_in_origin_comparison_for_testing_ = false;
CrawlingMode crawling_mode_ = CrawlingMode::kJustInTimeInstallation;
base::WeakPtrFactory<InstallablePaymentAppCrawler> weak_ptr_factory_{this}; base::WeakPtrFactory<InstallablePaymentAppCrawler> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(InstallablePaymentAppCrawler); DISALLOW_COPY_AND_ASSIGN(InstallablePaymentAppCrawler);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "components/payments/core/features.h" #include "components/payments/core/features.h"
#include "components/payments/core/method_strings.h" #include "components/payments/core/method_strings.h"
#include "components/payments/core/payment_manifest_downloader.h" #include "components/payments/core/payment_manifest_downloader.h"
#include "components/payments/core/url_util.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
...@@ -220,12 +221,35 @@ class SelfDeletingServiceWorkerPaymentAppFinder ...@@ -220,12 +221,35 @@ class SelfDeletingServiceWorkerPaymentAppFinder
const std::string& error_message) { const std::string& error_message) {
if (first_error_message_.empty()) if (first_error_message_.empty())
first_error_message_ = error_message; first_error_message_ = error_message;
if (apps.empty() && crawler_ != nullptr) {
std::set<GURL> method_manifest_urls_for_icon_refetch;
installed_apps_ = std::move(apps);
for (auto& app : installed_apps_) {
if (app.second->icon.get() && !app.second->icon.get()->drawsNothing()) {
continue;
}
for (const auto& method : app.second->enabled_methods) {
// Only payment methods with manifests are eligible for refetching the
// icon of their installed payment apps.
GURL method_manifest_url = GURL(method);
if (!UrlUtil::IsValidUrlBasedPaymentMethodIdentifier(
method_manifest_url)) {
continue;
}
method_manifest_urls_for_icon_refetch.insert(method_manifest_url);
}
}
if ((installed_apps_.empty() ||
!method_manifest_urls_for_icon_refetch.empty()) &&
crawler_ != nullptr) {
// Crawls installable web payment apps if no web payment apps have been // Crawls installable web payment apps if no web payment apps have been
// installed. // installed or when an installed app is missing an icon.
is_payment_app_crawler_finished_using_resources_ = false; is_payment_app_crawler_finished_using_resources_ = false;
crawler_->Start( crawler_->Start(
requested_method_data_, requested_method_data_,
std::move(method_manifest_urls_for_icon_refetch),
base::BindOnce( base::BindOnce(
&SelfDeletingServiceWorkerPaymentAppFinder::OnPaymentAppsCrawled, &SelfDeletingServiceWorkerPaymentAppFinder::OnPaymentAppsCrawled,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
...@@ -239,18 +263,36 @@ class SelfDeletingServiceWorkerPaymentAppFinder ...@@ -239,18 +263,36 @@ class SelfDeletingServiceWorkerPaymentAppFinder
crawler_.reset(); crawler_.reset();
std::move(callback_).Run( std::move(callback_).Run(
std::move(apps), std::move(installed_apps_),
ServiceWorkerPaymentAppFinder::InstallablePaymentApps(), ServiceWorkerPaymentAppFinder::InstallablePaymentApps(),
first_error_message_); first_error_message_);
} }
void OnPaymentAppsCrawled( void OnPaymentAppsCrawled(
std::map<GURL, std::unique_ptr<WebAppInstallationInfo>> apps_info, std::map<GURL, std::unique_ptr<WebAppInstallationInfo>> apps_info,
std::map<GURL, std::unique_ptr<SkBitmap>> refetched_icons,
const std::string& error_message) { const std::string& error_message) {
if (first_error_message_.empty()) if (first_error_message_.empty())
first_error_message_ = error_message; first_error_message_ = error_message;
std::move(callback_).Run(content::PaymentAppProvider::PaymentApps(),
std::move(apps_info), first_error_message_); for (auto& refetched_icon : refetched_icons) {
GURL web_app_manifest_url = refetched_icon.first;
for (auto& app : installed_apps_) {
// It is possible (unlikely) to have multiple apps with same origins.
// The proper validation is to store web_app_manifest_url in
// StoredPaymentApp and confirm that it is the same as the
// web_app_manifest_url from which icon is fetched.
if (crawler_->IsSameOriginWith(GURL(app.second->scope),
web_app_manifest_url)) {
// TODO(crbug.com/1069010): Update the payment app database with the
// new icon.
app.second->icon = std::move(refetched_icon.second);
break;
}
}
}
std::move(callback_).Run(std::move(installed_apps_), std::move(apps_info),
first_error_message_);
} }
void OnPaymentAppsCrawlerFinishedUsingResources() { void OnPaymentAppsCrawlerFinishedUsingResources() {
...@@ -304,6 +346,8 @@ class SelfDeletingServiceWorkerPaymentAppFinder ...@@ -304,6 +346,8 @@ class SelfDeletingServiceWorkerPaymentAppFinder
bool ignore_port_in_origin_comparison_for_testing_ = false; bool ignore_port_in_origin_comparison_for_testing_ = false;
content::PaymentAppProvider::PaymentApps installed_apps_;
base::WeakPtrFactory<SelfDeletingServiceWorkerPaymentAppFinder> base::WeakPtrFactory<SelfDeletingServiceWorkerPaymentAppFinder>
weak_ptr_factory_{this}; weak_ptr_factory_{this};
}; };
......
...@@ -62,5 +62,9 @@ const base::Feature kDownRankJustInTimePaymentApp{ ...@@ -62,5 +62,9 @@ const base::Feature kDownRankJustInTimePaymentApp{
const base::Feature kPaymentHandlerPopUpSizeWindow{ const base::Feature kPaymentHandlerPopUpSizeWindow{
"PaymentHandlerPopUpSizeWindow", base::FEATURE_ENABLED_BY_DEFAULT}; "PaymentHandlerPopUpSizeWindow", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kAllowJITInstallationWhenAppIconIsMissing{
"AllowJITInstallationWhenAppIconIsMissing",
base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features } // namespace features
} // namespace payments } // namespace payments
...@@ -72,6 +72,9 @@ extern const base::Feature kDownRankJustInTimePaymentApp; ...@@ -72,6 +72,9 @@ extern const base::Feature kDownRankJustInTimePaymentApp;
// window size. // window size.
extern const base::Feature kPaymentHandlerPopUpSizeWindow; extern const base::Feature kPaymentHandlerPopUpSizeWindow;
// Used to test icon refetch for JIT installed apps with missing icons.
extern const base::Feature kAllowJITInstallationWhenAppIconIsMissing;
} // namespace features } // namespace features
} // namespace payments } // namespace payments
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment