blob: a697fad381f2e75c3e925461a7fe9f0232734f6c [file] [log] [blame]
// 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.
#include "components/payments/content/payment_handler_host.h"
#include <utility>
#include "base/callback.h"
#include "base/strings/string_number_conversions.h"
#include "components/payments/core/error_strings.h"
#include "components/payments/core/native_error_strings.h"
#include "components/payments/core/payment_address.h"
#include "components/payments/core/payments_validators.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_background_services_context.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "url/origin.h"
namespace payments {
namespace {
content::DevToolsBackgroundServicesContext* GetDevTools(
content::BrowserContext* browser_context,
const url::Origin& sw_origin) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto* storage_partition = content::BrowserContext::GetStoragePartitionForSite(
browser_context, sw_origin.GetURL(), /*can_create=*/true);
if (!storage_partition)
return nullptr;
auto* dev_tools = storage_partition->GetDevToolsBackgroundServicesContext();
return dev_tools && dev_tools->IsRecording(
content::DevToolsBackgroundService::kPaymentHandler)
? dev_tools
: nullptr;
}
// Generates a PaymentResponse with the given error, then runs the provided
// callback.
void RunCallbackWithError(const std::string& error,
ChangePaymentRequestDetailsCallback callback) {
mojom::PaymentRequestDetailsUpdatePtr response =
mojom::PaymentRequestDetailsUpdate::New();
response->error = error;
std::move(callback).Run(std::move(response));
}
} // namespace
PaymentHandlerHost::PaymentHandlerHost(content::WebContents* web_contents,
Delegate* delegate)
: web_contents_(web_contents), delegate_(delegate) {
DCHECK(web_contents_);
DCHECK(delegate_);
}
PaymentHandlerHost::~PaymentHandlerHost() {}
mojo::PendingRemote<mojom::PaymentHandlerHost> PaymentHandlerHost::Bind() {
receiver_.reset();
mojo::PendingRemote<mojom::PaymentHandlerHost> host =
receiver_.BindNewPipeAndPassRemote();
// Connection error handler can be set only after the Bind() call.
receiver_.set_disconnect_handler(base::BindOnce(
&PaymentHandlerHost::Disconnect, weak_ptr_factory_.GetWeakPtr()));
return host;
}
void PaymentHandlerHost::UpdateWith(
mojom::PaymentRequestDetailsUpdatePtr response) {
if (!change_payment_request_details_callback_)
return;
auto* dev_tools =
GetDevTools(web_contents_->GetBrowserContext(), sw_origin_for_logs_);
if (dev_tools) {
std::map<std::string, std::string> data = {{"Error", response->error}};
if (response->total) {
data["Total Currency"] = response->total->currency;
data["Total Value"] = response->total->value;
}
if (response->stringified_payment_method_errors) {
data["Payment Method Errors"] =
*response->stringified_payment_method_errors;
}
if (response->shipping_address_errors) {
data["Shipping Address Address Line Error"] =
response->shipping_address_errors->address_line;
data["Shipping Address City Error"] =
response->shipping_address_errors->city;
data["Shipping Address Country Error"] =
response->shipping_address_errors->country;
data["Shipping Address Dependent Locality Error"] =
response->shipping_address_errors->dependent_locality;
data["Shipping Address Organization Error"] =
response->shipping_address_errors->organization;
data["Shipping Address Phone Error"] =
response->shipping_address_errors->phone;
data["Shipping Address Postal Code Error"] =
response->shipping_address_errors->postal_code;
data["Shipping Address Recipient Error"] =
response->shipping_address_errors->recipient;
data["Shipping Address Region Error"] =
response->shipping_address_errors->region;
data["Shipping Address Sorting Code Error"] =
response->shipping_address_errors->sorting_code;
}
if (response->modifiers) {
for (size_t i = 0; i < response->modifiers->size(); ++i) {
std::string prefix =
"Modifier" + (response->modifiers->size() == 1
? ""
: " #" + base::NumberToString(i));
const auto& modifier = response->modifiers->at(i);
data.emplace(prefix + " Method Name",
modifier->method_data->method_name);
data.emplace(prefix + " Method Data",
modifier->method_data->stringified_data);
if (!modifier->total)
continue;
data.emplace(prefix + " Total Currency", modifier->total->currency);
data.emplace(prefix + " Total Value", modifier->total->value);
}
}
if (response->shipping_options) {
for (size_t i = 0; i < response->shipping_options->size(); ++i) {
std::string prefix =
"Shipping Option" + (response->shipping_options->size() == 1
? ""
: " #" + base::NumberToString(i));
const auto& option = response->shipping_options->at(i);
data.emplace(prefix + " Id", option->id);
data.emplace(prefix + " Label", option->label);
data.emplace(prefix + " Amount Currency", option->amount->currency);
data.emplace(prefix + " Amount Value", option->amount->value);
data.emplace(prefix + " Selected", option->selected ? "true" : "false");
}
}
dev_tools->LogBackgroundServiceEvent(
registration_id_for_logs_, sw_origin_for_logs_,
content::DevToolsBackgroundService::kPaymentHandler, "Update with",
/*instance_id=*/payment_request_id_for_logs_, data);
}
std::move(change_payment_request_details_callback_).Run(std::move(response));
}
void PaymentHandlerHost::NoUpdatedPaymentDetails() {
if (!change_payment_request_details_callback_)
return;
std::move(change_payment_request_details_callback_)
.Run(mojom::PaymentRequestDetailsUpdate::New());
}
void PaymentHandlerHost::Disconnect() {
receiver_.reset();
}
base::WeakPtr<PaymentHandlerHost> PaymentHandlerHost::AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void PaymentHandlerHost::ChangePaymentMethod(
mojom::PaymentHandlerMethodDataPtr method_data,
ChangePaymentRequestDetailsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!method_data) {
RunCallbackWithError(errors::kMethodDataRequired, std::move(callback));
return;
}
if (method_data->method_name.empty()) {
RunCallbackWithError(errors::kMethodNameRequired, std::move(callback));
return;
}
if (!delegate_->ChangePaymentMethod(method_data->method_name,
method_data->stringified_data)) {
RunCallbackWithError(errors::kInvalidState, std::move(callback));
return;
}
auto* dev_tools =
GetDevTools(web_contents_->GetBrowserContext(), sw_origin_for_logs_);
if (dev_tools) {
dev_tools->LogBackgroundServiceEvent(
registration_id_for_logs_, sw_origin_for_logs_,
content::DevToolsBackgroundService::kPaymentHandler,
"Change payment method",
/*instance_id=*/payment_request_id_for_logs_,
{{"Method Name", method_data->method_name},
{"Method Data", method_data->stringified_data}});
}
change_payment_request_details_callback_ = std::move(callback);
}
void PaymentHandlerHost::ChangeShippingOption(
const std::string& shipping_option_id,
ChangePaymentRequestDetailsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (shipping_option_id.empty()) {
RunCallbackWithError(errors::kShippingOptionIdRequired,
std::move(callback));
return;
}
if (!delegate_->ChangeShippingOption(shipping_option_id)) {
RunCallbackWithError(errors::kInvalidState, std::move(callback));
return;
}
auto* dev_tools =
GetDevTools(web_contents_->GetBrowserContext(), sw_origin_for_logs_);
if (dev_tools) {
dev_tools->LogBackgroundServiceEvent(
registration_id_for_logs_, sw_origin_for_logs_,
content::DevToolsBackgroundService::kPaymentHandler,
"Change shipping option",
/*instance_id=*/payment_request_id_for_logs_,
{{"Shipping Option Id", shipping_option_id}});
}
change_payment_request_details_callback_ = std::move(callback);
}
void PaymentHandlerHost::ChangeShippingAddress(
mojom::PaymentAddressPtr shipping_address,
ChangePaymentRequestDetailsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!shipping_address || !PaymentsValidators::IsValidCountryCodeFormat(
shipping_address->country, nullptr)) {
RunCallbackWithError(errors::kShippingAddressInvalid, std::move(callback));
return;
}
if (!delegate_->ChangeShippingAddress(shipping_address.Clone())) {
RunCallbackWithError(errors::kInvalidState, std::move(callback));
return;
}
auto* dev_tools =
GetDevTools(web_contents_->GetBrowserContext(), sw_origin_for_logs_);
if (dev_tools) {
std::map<std::string, std::string> shipping_address_map;
shipping_address_map.emplace("Country", shipping_address->country);
for (size_t i = 0; i < shipping_address->address_line.size(); ++i) {
std::string key =
"Address Line" + (shipping_address->address_line.size() == 1
? ""
: " #" + base::NumberToString(i));
shipping_address_map.emplace(key, shipping_address->address_line[i]);
}
shipping_address_map.emplace("Region", shipping_address->region);
shipping_address_map.emplace("City", shipping_address->city);
shipping_address_map.emplace("Dependent Locality",
shipping_address->dependent_locality);
shipping_address_map.emplace("Postal Code", shipping_address->postal_code);
shipping_address_map.emplace("Sorting Code",
shipping_address->sorting_code);
shipping_address_map.emplace("Organization",
shipping_address->organization);
shipping_address_map.emplace("Recipient", shipping_address->recipient);
shipping_address_map.emplace("Phone", shipping_address->phone);
dev_tools->LogBackgroundServiceEvent(
registration_id_for_logs_, sw_origin_for_logs_,
content::DevToolsBackgroundService::kPaymentHandler,
"Change shipping address",
/*instance_id=*/payment_request_id_for_logs_, shipping_address_map);
}
change_payment_request_details_callback_ = std::move(callback);
}
} // namespace payments