blob: 7114de62c79e58efb48521e65ec62b40e5f7bddb [file] [log] [blame]
// Copyright 2018 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/content/installable_payment_app_crawler.h"
#include <utility>
#include "content/public/browser/browser_thread.h"
#include "url/gurl.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(
PaymentManifestDownloader* downloader,
PaymentManifestParser* parser,
PaymentManifestWebDataService* cache)
: downloader_(downloader),
parser_(parser),
number_of_payment_method_manifest_to_download_(0),
number_of_payment_method_manifest_to_parse_(0),
number_of_web_app_manifest_to_download_(0),
number_of_web_app_manifest_to_parse_(0),
weak_ptr_factory_(this) {}
InstallablePaymentAppCrawler::~InstallablePaymentAppCrawler() {}
void InstallablePaymentAppCrawler::Start(
const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data,
FinishedCrawlingCallback callback,
base::OnceClosure finished_using_resources) {
callback_ = std::move(callback);
finished_using_resources_ = std::move(finished_using_resources);
std::set<GURL> manifests_to_download;
for (const auto& method_data : requested_method_data) {
for (const auto& method_name : method_data->supported_methods) {
if (!base::IsStringUTF8(method_name))
continue;
GURL url = GURL(method_name);
if (url.is_valid()) {
manifests_to_download.insert(url);
}
}
}
if (manifests_to_download.empty()) {
// Post the result back asynchronously.
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::BindOnce(
&InstallablePaymentAppCrawler::FinishCrawlingPaymentAppsIfReady,
weak_ptr_factory_.GetWeakPtr()));
return;
}
number_of_payment_method_manifest_to_download_ = manifests_to_download.size();
for (const auto& url : manifests_to_download) {
downloader_->DownloadPaymentMethodManifest(
url,
base::BindOnce(
&InstallablePaymentAppCrawler::OnPaymentMethodManifestDownloaded,
weak_ptr_factory_.GetWeakPtr(), url));
}
}
void InstallablePaymentAppCrawler::OnPaymentMethodManifestDownloaded(
const GURL& method_manifest_url,
const std::string& content) {
number_of_payment_method_manifest_to_download_--;
if (content.empty()) {
FinishCrawlingPaymentAppsIfReady();
return;
}
number_of_payment_method_manifest_to_parse_++;
parser_->ParsePaymentMethodManifest(
content, base::BindOnce(
&InstallablePaymentAppCrawler::OnPaymentMethodManifestParsed,
weak_ptr_factory_.GetWeakPtr(), method_manifest_url));
}
void InstallablePaymentAppCrawler::OnPaymentMethodManifestParsed(
const GURL& method_manifest_url,
const std::vector<GURL>& default_applications,
const std::vector<url::Origin>& supported_origins,
bool all_origins_supported) {
number_of_payment_method_manifest_to_parse_--;
for (const auto& url : default_applications) {
if (downloaded_web_app_manifests_.find(url) !=
downloaded_web_app_manifests_.end()) {
// Do not download the same web app manifest again since a web app could
// be the default application of multiple payment methods.
continue;
}
number_of_web_app_manifest_to_download_++;
downloaded_web_app_manifests_.insert(url);
downloader_->DownloadWebAppManifest(
url,
base::BindOnce(
&InstallablePaymentAppCrawler::OnPaymentWebAppManifestDownloaded,
weak_ptr_factory_.GetWeakPtr(), method_manifest_url, url));
}
FinishCrawlingPaymentAppsIfReady();
}
void InstallablePaymentAppCrawler::OnPaymentWebAppManifestDownloaded(
const GURL& method_manifest_url,
const GURL& web_app_manifest_url,
const std::string& content) {
number_of_web_app_manifest_to_download_--;
if (content.empty()) {
FinishCrawlingPaymentAppsIfReady();
return;
}
number_of_web_app_manifest_to_parse_++;
parser_->ParseWebAppInstallationInfo(
content,
base::BindOnce(
&InstallablePaymentAppCrawler::OnPaymentWebAppInstallationInfo,
weak_ptr_factory_.GetWeakPtr(), method_manifest_url,
web_app_manifest_url));
}
void InstallablePaymentAppCrawler::OnPaymentWebAppInstallationInfo(
const GURL& method_manifest_url,
const GURL& web_app_manifest_url,
std::unique_ptr<WebAppInstallationInfo> app_info) {
number_of_web_app_manifest_to_parse_--;
if (app_info != nullptr) {
if (app_info->sw_js_url.empty() ||
!base::IsStringUTF8(app_info->sw_js_url)) {
FinishCrawlingPaymentAppsIfReady();
LOG(ERROR) << "The installable payment app's js url is not a non-empty "
"UTF8 string.";
return;
}
// Check and complete relative url.
if (!GURL(app_info->sw_js_url).is_valid()) {
GURL absolute_url = web_app_manifest_url.Resolve(app_info->sw_js_url);
if (!absolute_url.is_valid()) {
LOG(ERROR) << "Failed to resolve the installable payment app's js url.";
FinishCrawlingPaymentAppsIfReady();
return;
}
app_info->sw_js_url = absolute_url.spec();
}
if (!GURL(app_info->sw_scope).is_valid()) {
GURL absolute_scope =
web_app_manifest_url.GetWithoutFilename().Resolve(app_info->sw_scope);
if (!absolute_scope.is_valid()) {
LOG(ERROR) << "Failed to resolve the installable payment app's "
"registration scope.";
FinishCrawlingPaymentAppsIfReady();
return;
}
app_info->sw_scope = absolute_scope.spec();
}
installable_apps_[method_manifest_url] = std::move(app_info);
}
FinishCrawlingPaymentAppsIfReady();
}
void InstallablePaymentAppCrawler::FinishCrawlingPaymentAppsIfReady() {
if (number_of_payment_method_manifest_to_download_ != 0 ||
number_of_payment_method_manifest_to_parse_ != 0 ||
number_of_web_app_manifest_to_download_ != 0 ||
number_of_web_app_manifest_to_parse_ != 0) {
return;
}
std::move(callback_).Run(std::move(installable_apps_));
std::move(finished_using_resources_).Run();
}
} // namespace payments.