blob: 4b3825ec48c8a1aa665ebdbc2a34326d81c2ffdb [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 "third_party/blink/renderer/modules/push_messaging/push_messaging_client.h"
#include <string>
#include <utility>
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/mojom/manifest/manifest.mojom-blink.h"
#include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/modules/manifest/manifest_manager.h"
#include "third_party/blink/renderer/modules/push_messaging/push_error.h"
#include "third_party/blink/renderer/modules/push_messaging/push_messaging_utils.h"
#include "third_party/blink/renderer/modules/push_messaging/push_subscription.h"
#include "third_party/blink/renderer/modules/push_messaging/push_subscription_options.h"
#include "third_party/blink/renderer/modules/push_messaging/push_type_converter.h"
#include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
namespace blink {
// static
const char PushMessagingClient::kSupplementName[] = "PushMessagingClient";
PushMessagingClient::PushMessagingClient(LocalDOMWindow& window)
: Supplement<LocalDOMWindow>(window), push_messaging_manager_(&window) {
// This class will be instantiated for every page load (rather than on push
// messaging use), so there's nothing to be done in this constructor.
}
// static
PushMessagingClient* PushMessagingClient::From(LocalDOMWindow& window) {
auto* client = Supplement<LocalDOMWindow>::From<PushMessagingClient>(window);
if (!client) {
client = MakeGarbageCollected<PushMessagingClient>(window);
Supplement<LocalDOMWindow>::ProvideTo(window, client);
}
return client;
}
mojom::blink::PushMessaging* PushMessagingClient::GetPushMessagingRemote() {
if (!push_messaging_manager_.is_bound()) {
GetSupplementable()->GetBrowserInterfaceBroker().GetInterface(
push_messaging_manager_.BindNewPipeAndPassReceiver(
GetSupplementable()->GetTaskRunner(TaskType::kMiscPlatformAPI)));
}
return push_messaging_manager_.get();
}
void PushMessagingClient::Subscribe(
ServiceWorkerRegistration* service_worker_registration,
PushSubscriptionOptions* options,
bool user_gesture,
std::unique_ptr<PushSubscriptionCallbacks> callbacks) {
DCHECK(callbacks);
mojom::blink::PushSubscriptionOptionsPtr options_ptr =
mojo::ConvertTo<mojom::blink::PushSubscriptionOptionsPtr>(options);
// If a developer provided an application server key in |options|, skip
// fetching the manifest.
if (!options->applicationServerKey()->ByteLength()) {
ManifestManager* manifest_manager =
ManifestManager::From(*GetSupplementable());
manifest_manager->RequestManifest(
WTF::Bind(&PushMessagingClient::DidGetManifest, WrapPersistent(this),
WrapPersistent(service_worker_registration),
std::move(options_ptr), user_gesture, std::move(callbacks)));
} else {
DoSubscribe(service_worker_registration, std::move(options_ptr),
user_gesture, std::move(callbacks));
}
}
void PushMessagingClient::Trace(Visitor* visitor) const {
Supplement<LocalDOMWindow>::Trace(visitor);
visitor->Trace(push_messaging_manager_);
}
void PushMessagingClient::DidGetManifest(
ServiceWorkerRegistration* service_worker_registration,
mojom::blink::PushSubscriptionOptionsPtr options,
bool user_gesture,
std::unique_ptr<PushSubscriptionCallbacks> callbacks,
const KURL& manifest_url,
mojom::blink::ManifestPtr manifest) {
// Get the application_server_key from the manifest since it wasn't provided
// by the caller.
if (manifest == mojom::blink::Manifest::New()) {
DidSubscribe(
service_worker_registration, std::move(callbacks),
mojom::blink::PushRegistrationStatus::MANIFEST_EMPTY_OR_MISSING,
nullptr /* subscription */);
return;
}
if (!manifest->gcm_sender_id.IsNull()) {
StringUTF8Adaptor gcm_sender_id_as_utf8_string(manifest->gcm_sender_id);
Vector<uint8_t> application_server_key;
application_server_key.Append(gcm_sender_id_as_utf8_string.data(),
gcm_sender_id_as_utf8_string.size());
options->application_server_key = std::move(application_server_key);
}
DoSubscribe(service_worker_registration, std::move(options), user_gesture,
std::move(callbacks));
}
void PushMessagingClient::DoSubscribe(
ServiceWorkerRegistration* service_worker_registration,
mojom::blink::PushSubscriptionOptionsPtr options,
bool user_gesture,
std::unique_ptr<PushSubscriptionCallbacks> callbacks) {
DCHECK(callbacks);
if (options->application_server_key.IsEmpty()) {
DidSubscribe(service_worker_registration, std::move(callbacks),
mojom::blink::PushRegistrationStatus::NO_SENDER_ID,
nullptr /* subscription */);
return;
}
GetPushMessagingRemote()->Subscribe(
service_worker_registration->RegistrationId(), std::move(options),
user_gesture,
WTF::Bind(&PushMessagingClient::DidSubscribe, WrapPersistent(this),
WrapPersistent(service_worker_registration),
std::move(callbacks)));
}
void PushMessagingClient::DidSubscribe(
ServiceWorkerRegistration* service_worker_registration,
std::unique_ptr<PushSubscriptionCallbacks> callbacks,
mojom::blink::PushRegistrationStatus status,
mojom::blink::PushSubscriptionPtr subscription) {
DCHECK(callbacks);
if (status ==
mojom::blink::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE ||
status == mojom::blink::PushRegistrationStatus::
SUCCESS_NEW_SUBSCRIPTION_FROM_PUSH_SERVICE ||
status == mojom::blink::PushRegistrationStatus::SUCCESS_FROM_CACHE) {
DCHECK(subscription);
callbacks->OnSuccess(PushSubscription::Create(std::move(subscription),
service_worker_registration));
} else {
callbacks->OnError(PushError::CreateException(
PushRegistrationStatusToPushErrorType(status),
PushRegistrationStatusToString(status)));
}
}
} // namespace blink